summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/device_pm.c23
-rw-r--r--drivers/acpi/dock.c7
-rw-r--r--drivers/acpi/fan.c2
-rw-r--r--drivers/acpi/power.c4
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/base/dma-buf.c5
-rw-r--r--drivers/char/hw_random/Kconfig2
-rw-r--r--drivers/clocksource/Kconfig18
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/arm_global_timer.c321
-rw-r--r--drivers/clocksource/time-orion.c150
-rw-r--r--drivers/cpufreq/cpufreq.c7
-rw-r--r--drivers/edac/Kconfig6
-rw-r--r--drivers/gpu/drm/drm_edid_load.c6
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/ide/delkin_cb.c13
-rw-r--r--drivers/ide/gayle.c15
-rw-r--r--drivers/ide/ide-taskfile.c5
-rw-r--r--drivers/ide/tx4938ide.c13
-rw-r--r--drivers/ide/tx4939ide.c13
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/Makefile1
-rw-r--r--drivers/infiniband/core/addr.c20
-rw-r--r--drivers/infiniband/core/cma.c906
-rw-r--r--drivers/infiniband/core/sa_query.c6
-rw-r--r--drivers/infiniband/core/sysfs.c8
-rw-r--r--drivers/infiniband/core/ucma.c321
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c1
-rw-r--r--drivers/infiniband/hw/mlx5/Kconfig10
-rw-r--r--drivers/infiniband/hw/mlx5/Makefile3
-rw-r--r--drivers/infiniband/hw/mlx5/ah.c92
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c843
-rw-r--r--drivers/infiniband/hw/mlx5/doorbell.c100
-rw-r--r--drivers/infiniband/hw/mlx5/mad.c139
-rw-r--r--drivers/infiniband/hw/mlx5/main.c1504
-rw-r--r--drivers/infiniband/hw/mlx5/mem.c162
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h545
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c1007
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c2524
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c473
-rw-r--r--drivers/infiniband/hw/mlx5/user.h121
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h63
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c86
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h35
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c135
-rw-r--r--drivers/infiniband/hw/qib/Kconfig8
-rw-r--r--drivers/infiniband/hw/qib/Makefile1
-rw-r--r--drivers/infiniband/hw/qib/qib.h63
-rw-r--r--drivers/infiniband/hw/qib/qib_common.h2
-rw-r--r--drivers/infiniband/hw/qib/qib_cq.c67
-rw-r--r--drivers/infiniband/hw/qib/qib_debugfs.c283
-rw-r--r--drivers/infiniband/hw/qib/qib_debugfs.h45
-rw-r--r--drivers/infiniband/hw/qib/qib_driver.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c176
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c10
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c10
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c507
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c145
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c123
-rw-r--r--drivers/infiniband/hw/qib/qib_sdma.c56
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h33
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c268
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h5
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c89
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c27
-rw-r--r--drivers/iommu/Kconfig13
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/amd_iommu.c104
-rw-r--r--drivers/iommu/arm-smmu.c1969
-rw-r--r--drivers/iommu/dmar.c4
-rw-r--r--drivers/iommu/intel-iommu.c25
-rw-r--r--drivers/iommu/intel_irq_remapping.c3
-rw-r--r--drivers/iommu/iommu.c86
-rw-r--r--drivers/iommu/omap-iommu.c15
-rw-r--r--drivers/iommu/omap-iopgtable.h2
-rw-r--r--drivers/iommu/omap-iovmm.c4
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-moxart.c117
-rw-r--r--drivers/irqchip/irq-nvic.c2
-rw-r--r--drivers/irqchip/irq-sun4i.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c6
-rw-r--r--drivers/md/Kconfig14
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/dm-bufio.c75
-rw-r--r--drivers/md/dm-cache-target.c4
-rw-r--r--drivers/md/dm-flakey.c2
-rw-r--r--drivers/md/dm-ioctl.c127
-rw-r--r--drivers/md/dm-mpath.c8
-rw-r--r--drivers/md/dm-switch.c538
-rw-r--r--drivers/md/dm-table.c35
-rw-r--r--drivers/md/dm-verity.c17
-rw-r--r--drivers/md/dm.c177
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c23
-rw-r--r--drivers/media/common/siano/smscoreapi.c23
-rw-r--r--drivers/media/common/siano/smsdvb-main.c1
-rw-r--r--drivers/media/common/tveeprom.c142
-rw-r--r--drivers/media/dvb-core/dmxdev.c8
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h2
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c21
-rw-r--r--drivers/media/dvb-frontends/dib8000.c4
-rw-r--r--drivers/media/dvb-frontends/drxk.h2
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c3154
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.h277
-rw-r--r--drivers/media/dvb-frontends/stb0899_algo.c105
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c5
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.h5
-rw-r--r--drivers/media/i2c/Kconfig18
-rw-r--r--drivers/media/i2c/Makefile2
-rw-r--r--drivers/media/i2c/ad9389b.c35
-rw-r--r--drivers/media/i2c/adp1653.c5
-rw-r--r--drivers/media/i2c/adv7170.c16
-rw-r--r--drivers/media/i2c/adv7175.c12
-rw-r--r--drivers/media/i2c/adv7180.c79
-rw-r--r--drivers/media/i2c/adv7183.c80
-rw-r--r--drivers/media/i2c/adv7343.c10
-rw-r--r--drivers/media/i2c/adv7393.c18
-rw-r--r--drivers/media/i2c/adv7604.c33
-rw-r--r--drivers/media/i2c/ak881x.c39
-rw-r--r--drivers/media/i2c/as3645a.c7
-rw-r--r--drivers/media/i2c/bt819.c26
-rw-r--r--drivers/media/i2c/bt856.c12
-rw-r--r--drivers/media/i2c/bt866.c16
-rw-r--r--drivers/media/i2c/cs5345.c25
-rw-r--r--drivers/media/i2c/cs53l32a.c14
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c72
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.h34
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c7
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c10
-rw-r--r--drivers/media/i2c/ks0127.c36
-rw-r--r--drivers/media/i2c/m52790.c22
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c43
-rw-r--r--drivers/media/i2c/ml86v7667.c431
-rw-r--r--drivers/media/i2c/msp3400-driver.c15
-rw-r--r--drivers/media/i2c/mt9m032.c13
-rw-r--r--drivers/media/i2c/mt9p031.c87
-rw-r--r--drivers/media/i2c/mt9t001.c4
-rw-r--r--drivers/media/i2c/mt9v011.c34
-rw-r--r--drivers/media/i2c/mt9v032.c8
-rw-r--r--drivers/media/i2c/noon010pc30.c41
-rw-r--r--drivers/media/i2c/ov7640.c6
-rw-r--r--drivers/media/i2c/ov7670.c26
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c88
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c4
-rw-r--r--drivers/media/i2c/s5k6aa.c73
-rw-r--r--drivers/media/i2c/saa6588.c19
-rw-r--r--drivers/media/i2c/saa7110.c17
-rw-r--r--drivers/media/i2c/saa7115.c297
-rw-r--r--drivers/media/i2c/saa7127.c55
-rw-r--r--drivers/media/i2c/saa717x.c16
-rw-r--r--drivers/media/i2c/saa7185.c12
-rw-r--r--drivers/media/i2c/saa7191.c28
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c20
-rw-r--r--drivers/media/i2c/soc_camera/imx074.c51
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c50
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c53
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c54
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c35
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c64
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c35
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c39
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c29
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c31
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c35
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.h1
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c35
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c48
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c33
-rw-r--r--drivers/media/i2c/sony-btf-mpx.c5
-rw-r--r--drivers/media/i2c/sr030pc30.c280
-rw-r--r--drivers/media/i2c/tda7432.c4
-rw-r--r--drivers/media/i2c/tda9840.c16
-rw-r--r--drivers/media/i2c/tea6415c.c16
-rw-r--r--drivers/media/i2c/tea6420.c16
-rw-r--r--drivers/media/i2c/ths7303.c81
-rw-r--r--drivers/media/i2c/ths8200.c556
-rw-r--r--drivers/media/i2c/ths8200_regs.h161
-rw-r--r--drivers/media/i2c/tlv320aic23b.c4
-rw-r--r--drivers/media/i2c/tvaudio.c14
-rw-r--r--drivers/media/i2c/tvp514x.c87
-rw-r--r--drivers/media/i2c/tvp5150.c50
-rw-r--r--drivers/media/i2c/tvp7002.c143
-rw-r--r--drivers/media/i2c/tw2804.c6
-rw-r--r--drivers/media/i2c/tw9903.c5
-rw-r--r--drivers/media/i2c/tw9906.c5
-rw-r--r--drivers/media/i2c/uda1342.c3
-rw-r--r--drivers/media/i2c/upd64031a.c24
-rw-r--r--drivers/media/i2c/upd64083.c24
-rw-r--r--drivers/media/i2c/vp27smpx.c12
-rw-r--r--drivers/media/i2c/vpx3220.c29
-rw-r--r--drivers/media/i2c/vs6624.c46
-rw-r--r--drivers/media/i2c/wm8739.c13
-rw-r--r--drivers/media/i2c/wm8775.c13
-rw-r--r--drivers/media/media-device.c3
-rw-r--r--drivers/media/media-entity.c81
-rw-r--r--drivers/media/parport/bw-qcam.c2
-rw-r--r--drivers/media/pci/Kconfig4
-rw-r--r--drivers/media/pci/b2c2/flexcop-pci.c13
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c52
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c48
-rw-r--r--drivers/media/pci/bt8xx/bttv.h4
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c36
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.h1
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c82
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c145
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c9
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c31
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c12
-rw-r--r--drivers/media/pci/cx88/cx88-core.c7
-rw-r--r--drivers/media/pci/cx88/cx88-video.c25
-rw-r--r--drivers/media/pci/cx88/cx88.h8
-rw-r--r--drivers/media/pci/dm1105/dm1105.c13
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c8
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c45
-rw-r--r--drivers/media/pci/mantis/hopper_cards.c13
-rw-r--r--drivers/media/pci/mantis/mantis_cards.c13
-rw-r--r--drivers/media/pci/mantis/mantis_vp1041.c2
-rw-r--r--drivers/media/pci/pluto2/pluto2.c13
-rw-r--r--drivers/media/pci/pt1/pt1.c15
-rw-r--r--drivers/media/pci/saa7134/saa6752hs.c525
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c33
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c260
-rw-r--r--drivers/media/pci/saa7134/saa7134.h17
-rw-r--r--drivers/media/pci/saa7146/mxb.c23
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c8
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c58
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c24
-rw-r--r--drivers/media/pci/saa7164/saa7164.h5
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c3
-rw-r--r--drivers/media/pci/ttpci/budget-av.c2
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c2
-rw-r--r--drivers/media/pci/zoran/zoran_card.c2
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c23
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c81
-rw-r--r--drivers/media/platform/blackfin/ppi.c12
-rw-r--r--drivers/media/platform/coda.c635
-rw-r--r--drivers/media/platform/coda.h11
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c31
-rw-r--r--drivers/media/platform/davinci/vpbe_osd.c24
-rw-r--r--drivers/media/platform/davinci/vpif.c45
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c160
-rw-r--r--drivers/media/platform/davinci/vpif_capture.h5
-rw-r--r--drivers/media/platform/davinci/vpif_display.c153
-rw-r--r--drivers/media/platform/davinci/vpif_display.h5
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c2
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig5
-rw-r--r--drivers/media/platform/exynos4-is/Makefile5
-rw-r--r--drivers/media/platform/exynos4-is/common.c53
-rw-r--r--drivers/media/platform/exynos4-is/common.h16
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c412
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c11
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h15
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.c84
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c12
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.h12
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c130
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h21
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c55
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.h10
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c321
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h35
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c1
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c7
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c272
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h54
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c67
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/indycam.c12
-rw-r--r--drivers/media/platform/m2m-deinterlace.c1
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c4
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c67
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h9
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c4
-rw-r--r--drivers/media/platform/mem2mem_testdev.c3
-rw-r--r--drivers/media/platform/mx2_emmaprp.c1
-rw-r--r--drivers/media/platform/omap/omap_vout.c3
-rw-r--r--drivers/media/platform/omap24xxcam.c9
-rw-r--r--drivers/media/platform/omap24xxcam.h3
-rw-r--r--drivers/media/platform/omap3isp/isp.c51
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c2
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c21
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c2
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h1
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c6
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c2
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c6
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c2
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c39
-rw-r--r--drivers/media/platform/s5p-tv/mixer_drv.c22
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c3
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c22
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c4
-rw-r--r--drivers/media/platform/sh_veu.c5
-rw-r--r--drivers/media/platform/sh_vou.c34
-rw-r--r--drivers/media/platform/soc_camera/Kconfig12
-rw-r--r--drivers/media/platform/soc_camera/Makefile6
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c38
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c48
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c41
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c44
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c41
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c46
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c642
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c161
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c737
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c14
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.c402
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.h47
-rw-r--r--drivers/media/platform/timblogiw.c11
-rw-r--r--drivers/media/platform/via-camera.c24
-rw-r--r--drivers/media/radio/radio-keene.c7
-rw-r--r--drivers/media/radio/radio-sf16fmi.c127
-rw-r--r--drivers/media/radio/radio-si476x.c11
-rw-r--r--drivers/media/radio/radio-tea5764.c190
-rw-r--r--drivers/media/radio/radio-timb.c81
-rw-r--r--drivers/media/radio/saa7706h.c66
-rw-r--r--drivers/media/radio/tef6862.c24
-rw-r--r--drivers/media/radio/wl128x/fmdrv.h2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c24
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c8
-rw-r--r--drivers/media/rc/gpio-ir-recv.c2
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-delock-61959.c83
-rw-r--r--drivers/media/tuners/r820t.c18
-rw-r--r--drivers/media/usb/Kconfig5
-rw-r--r--drivers/media/usb/Makefile1
-rw-r--r--drivers/media/usb/au0828/au0828-video.c40
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c424
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c66
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h11
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c5
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c90
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c180
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h6
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c2
-rw-r--r--drivers/media/usb/dvb-usb/pctv452e.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c239
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c27
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c73
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h23
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c66
-rw-r--r--drivers/media/usb/em28xx/em28xx.h7
-rw-r--r--drivers/media/usb/gspca/gspca.c32
-rw-r--r--drivers/media/usb/gspca/gspca.h6
-rw-r--r--drivers/media/usb/gspca/pac7302.c19
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c69
-rw-r--r--drivers/media/usb/hdpvr/Kconfig2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-control.c34
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c8
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c110
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c42
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h13
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c43
-rw-r--r--drivers/media/usb/sn9c102/sn9c102.h3
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_core.c13
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c41
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c13
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c2
-rw-r--r--drivers/media/usb/usbtv/Kconfig10
-rw-r--r--drivers/media/usb/usbtv/Makefile1
-rw-r--r--drivers/media/usb/usbtv/usbtv.c696
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c19
-rw-r--r--drivers/media/usb/uvc/Kconfig1
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c41
-rw-r--r--drivers/media/usb/uvc/uvc_status.c21
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c14
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h7
-rw-r--r--drivers/media/v4l2-core/Makefile3
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c284
-rw-r--r--drivers/media/v4l2-core/v4l2-clk.c242
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c60
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c40
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c13
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c83
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c19
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c10
-rw-r--r--drivers/media/v4l2-core/videobuf-vmalloc.c10
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c4
-rw-r--r--drivers/net/ethernet/mellanox/Kconfig1
-rw-r--r--drivers/net/ethernet/mellanox/Makefile1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/alloc.c238
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c1515
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c224
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/debugfs.c583
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c521
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c185
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c227
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mad.c78
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c475
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mcg.c106
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h73
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mr.c136
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c435
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pd.c101
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c104
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/qp.c301
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/srq.c223
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/uar.c223
-rw-r--r--drivers/net/ethernet/octeon/Kconfig2
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c2
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/virtio_net.c5
-rw-r--r--drivers/rapidio/switches/idt_gen2.c2
-rw-r--r--drivers/remoteproc/remoteproc_core.c24
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c3
-rw-r--r--drivers/remoteproc/remoteproc_internal.h4
-rw-r--r--drivers/scsi/constants.c235
-rw-r--r--drivers/scsi/fcoe/fcoe.c26
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c4
-rw-r--r--drivers/scsi/fcoe/fcoe_sysfs.c24
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c28
-rw-r--r--drivers/scsi/libfc/fc_exch.c4
-rw-r--r--drivers/scsi/libfc/fc_rport.c27
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c10
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c4
-rw-r--r--drivers/scsi/mpt3sas/Kconfig2
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2.h12
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h15
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_init.h2
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_ioc.h10
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_raid.h10
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_sas.h2
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_tool.h10
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_type.h2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c22
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h8
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.h2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_debug.h2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c54
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c38
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h34
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c167
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h98
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c151
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c10
-rw-r--r--drivers/scsi/scsi_debug.c174
-rw-r--r--drivers/scsi/scsi_lib.c27
-rw-r--r--drivers/scsi/storvsc_drv.c139
-rw-r--r--drivers/spi/Kconfig2
-rw-r--r--drivers/ssb/Kconfig2
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c14
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c14
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c1
-rw-r--r--drivers/staging/media/go7007/go7007-usb.c4
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c7
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-tw28.c112
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c38
-rw-r--r--drivers/staging/octeon/Kconfig2
-rw-r--r--drivers/staging/ti-soc-thermal/ti_soc_thermal.txt61
-rw-r--r--drivers/target/iscsi/iscsi_target.c768
-rw-r--r--drivers/target/iscsi/iscsi_target.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c184
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h11
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c8
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c26
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c13
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c3
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c28
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h3
-rw-r--r--drivers/target/loopback/tcm_loop.c3
-rw-r--r--drivers/target/sbp/sbp_target.c3
-rw-r--r--drivers/target/target_core_configfs.c13
-rw-r--r--drivers/target/target_core_device.c5
-rw-r--r--drivers/target/target_core_fabric_configfs.c21
-rw-r--r--drivers/target/target_core_pr.c499
-rw-r--r--drivers/target/target_core_pr.h2
-rw-r--r--drivers/target/target_core_rd.c5
-rw-r--r--drivers/target/target_core_sbc.c18
-rw-r--r--drivers/target/target_core_tmr.c12
-rw-r--r--drivers/target/target_core_transport.c87
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h2
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c8
-rw-r--r--drivers/thermal/Kconfig15
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/armada_thermal.c3
-rw-r--r--drivers/thermal/cpu_cooling.c2
-rw-r--r--drivers/thermal/dove_thermal.c10
-rw-r--r--drivers/thermal/exynos_thermal.c3
-rw-r--r--drivers/thermal/kirkwood_thermal.c10
-rw-r--r--drivers/thermal/rcar_thermal.c10
-rw-r--r--drivers/thermal/spear_thermal.c20
-rw-r--r--drivers/thermal/thermal_core.c11
-rw-r--r--drivers/thermal/ti-soc-thermal/Kconfig (renamed from drivers/staging/ti-soc-thermal/Kconfig)12
-rw-r--r--drivers/thermal/ti-soc-thermal/Makefile (renamed from drivers/staging/ti-soc-thermal/Makefile)1
-rw-r--r--drivers/thermal/ti-soc-thermal/TODO (renamed from drivers/staging/ti-soc-thermal/TODO)0
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-bandgap.h280
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-thermal-data.c476
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap4-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap5-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.c)36
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.h (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.h)5
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c (renamed from drivers/staging/ti-soc-thermal/ti-thermal-common.c)15
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal.h (renamed from drivers/staging/ti-soc-thermal/ti-thermal.h)6
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c642
-rw-r--r--drivers/tty/serial/8250/8250_dw.c108
-rw-r--r--drivers/usb/gadget/f_uvc.c9
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c3
-rw-r--r--drivers/usb/gadget/uvc.h2
-rw-r--r--drivers/usb/host/Kconfig4
-rw-r--r--drivers/vfio/vfio.c14
-rw-r--r--drivers/vfio/vfio_iommu_type1.c626
-rw-r--r--drivers/vhost/Kconfig8
-rw-r--r--drivers/vhost/Makefile3
-rw-r--r--drivers/vhost/net.c4
-rw-r--r--drivers/vhost/scsi.c495
-rw-r--r--drivers/vhost/test.c33
-rw-r--r--drivers/vhost/vhost.c86
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--drivers/virtio/virtio_balloon.c3
-rw-r--r--drivers/virtio/virtio_pci.c5
-rw-r--r--drivers/watchdog/Kconfig36
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c17
-rw-r--r--drivers/watchdog/bcm2835_wdt.c189
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c9
-rw-r--r--drivers/watchdog/cpwd.c4
-rw-r--r--drivers/watchdog/da9052_wdt.c4
-rw-r--r--drivers/watchdog/da9055_wdt.c4
-rw-r--r--drivers/watchdog/dw_wdt.c11
-rw-r--r--drivers/watchdog/hpwdt.c11
-rw-r--r--drivers/watchdog/imx2_wdt.c6
-rw-r--r--drivers/watchdog/jz4740_wdt.c2
-rw-r--r--drivers/watchdog/mena21_wdt.c270
-rw-r--r--drivers/watchdog/mpcore_wdt.c456
-rw-r--r--drivers/watchdog/mtx-1_wdt.c3
-rw-r--r--drivers/watchdog/mv64x60_wdt.c4
-rw-r--r--drivers/watchdog/nuc900_wdt.c50
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c31
-rw-r--r--drivers/watchdog/orion_wdt.c7
-rw-r--r--drivers/watchdog/pnx4008_wdt.c7
-rw-r--r--drivers/watchdog/rc32434_wdt.c10
-rw-r--r--drivers/watchdog/riowd.c12
-rw-r--r--drivers/watchdog/s3c2410_wdt.c20
-rw-r--r--drivers/watchdog/sb_wdog.c2
-rw-r--r--drivers/watchdog/shwdt.c18
-rw-r--r--drivers/watchdog/softdog.c1
-rw-r--r--drivers/watchdog/sp805_wdt.c7
-rw-r--r--drivers/watchdog/ts72xx_wdt.c67
-rw-r--r--drivers/watchdog/twl4030_wdt.c5
-rw-r--r--drivers/watchdog/watchdog_dev.c6
-rw-r--r--drivers/watchdog/wdrtas.c29
-rw-r--r--drivers/watchdog/wm831x_wdt.c21
590 files changed, 34566 insertions, 13090 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index e9e8bb24785b..4ab807dc8518 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
if (result)
return result;
- if (state == ACPI_STATE_UNKNOWN)
+ if (state == ACPI_STATE_UNKNOWN) {
state = ACPI_STATE_D0;
-
- result = acpi_device_set_power(device, state);
- if (!result && state_p)
+ result = acpi_device_set_power(device, state);
+ if (result)
+ return result;
+ } else {
+ if (device->power.flags.power_resources) {
+ /*
+ * We don't need to really switch the state, bu we need
+ * to update the power resources' reference counters.
+ */
+ result = acpi_power_transition(device, state);
+ if (result)
+ return result;
+ }
+ device->power.state = state;
+ }
+ if (state_p)
*state_p = state;
- return result;
+ return 0;
}
EXPORT_SYMBOL_GPL(acpi_bus_update_power);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 14de9f46972e..826560753389 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -1064,10 +1064,10 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-int __init acpi_dock_init(void)
+void __init acpi_dock_init(void)
{
if (acpi_disabled)
- return 0;
+ return;
/* look for dock stations and bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
@@ -1075,11 +1075,10 @@ int __init acpi_dock_init(void)
if (!dock_station_count) {
pr_info(PREFIX "No dock devices found.\n");
- return 0;
+ return;
}
register_acpi_bus_notifier(&dock_acpi_notifier);
pr_info(PREFIX "%s: %d docks/bays found\n",
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
- return 0;
}
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 8d1c0105e113..5b02a0aa540c 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -84,7 +84,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
{
struct acpi_device *device = cdev->devdata;
int result;
- int acpi_state;
+ int acpi_state = ACPI_STATE_D0;
if (!device)
return -EINVAL;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 288bb270f8ed..5c28c894c0fc 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -279,7 +279,7 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
if (resource->ref_count++) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Power resource [%s] already on",
+ "Power resource [%s] already on\n",
resource->name));
} else {
result = __acpi_power_on(resource);
@@ -325,7 +325,7 @@ static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
if (!resource->ref_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Power resource [%s] already off",
+ "Power resource [%s] already off\n",
resource->name));
return 0;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index dfe76f17cfc4..10985573aaa7 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -35,7 +35,6 @@ bool acpi_force_hot_remove;
static const char *dummy_hid = "device";
-static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index aba6e93b0502..80dc988f01e4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -160,7 +160,7 @@ config PDC_ADMA
config PATA_OCTEON_CF
tristate "OCTEON Boot Bus Compact Flash support"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
help
This option enables a polled compact flash driver for use with
compact flash cards attached to the OCTEON boot bus.
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 08fe897c0b4c..6687ba741879 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -680,10 +680,7 @@ int dma_buf_debugfs_create_file(const char *name,
d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
write, &dma_buf_debug_fops);
- if (IS_ERR(d))
- return PTR_ERR(d);
-
- return 0;
+ return PTR_RET(d);
}
#else
static inline int dma_buf_init_debugfs(void)
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 2f9dbf7568fb..40a865449f35 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -167,7 +167,7 @@ config HW_RANDOM_OMAP
config HW_RANDOM_OCTEON
tristate "Octeon Random Number Generator support"
- depends on HW_RANDOM && CPU_CAVIUM_OCTEON
+ depends on HW_RANDOM && CAVIUM_OCTEON_SOC
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 81465c21f873..b7b9b040a89b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -27,6 +27,11 @@ config DW_APB_TIMER_OF
config ARMADA_370_XP_TIMER
bool
+config ORION_TIMER
+ select CLKSRC_OF
+ select CLKSRC_MMIO
+ bool
+
config SUN4I_TIMER
bool
@@ -69,6 +74,19 @@ config ARM_ARCH_TIMER
bool
select CLKSRC_OF if OF
+config ARM_GLOBAL_TIMER
+ bool
+ select CLKSRC_OF if OF
+ help
+ This options enables support for the ARM global timer unit
+
+config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ bool
+ depends on ARM_GLOBAL_TIMER
+ default y
+ help
+ Use ARM global timer clock source as sched_clock
+
config CLKSRC_METAG_GENERIC
def_bool y if METAG
help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 9ba8b4d867e3..8b00c5cebfa4 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
+obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
@@ -30,5 +31,6 @@ obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
+obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
new file mode 100644
index 000000000000..db8afc7427a6
--- /dev/null
+++ b/drivers/clocksource/arm_global_timer.c
@@ -0,0 +1,321 @@
+/*
+ * drivers/clocksource/arm_global_timer.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.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/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+
+#include <asm/cputype.h>
+
+#define GT_COUNTER0 0x00
+#define GT_COUNTER1 0x04
+
+#define GT_CONTROL 0x08
+#define GT_CONTROL_TIMER_ENABLE BIT(0) /* this bit is NOT banked */
+#define GT_CONTROL_COMP_ENABLE BIT(1) /* banked */
+#define GT_CONTROL_IRQ_ENABLE BIT(2) /* banked */
+#define GT_CONTROL_AUTO_INC BIT(3) /* banked */
+
+#define GT_INT_STATUS 0x0c
+#define GT_INT_STATUS_EVENT_FLAG BIT(0)
+
+#define GT_COMP0 0x10
+#define GT_COMP1 0x14
+#define GT_AUTO_INC 0x18
+
+/*
+ * We are expecting to be clocked by the ARM peripheral clock.
+ *
+ * Note: it is assumed we are using a prescaler value of zero, so this is
+ * the units for all operations.
+ */
+static void __iomem *gt_base;
+static unsigned long gt_clk_rate;
+static int gt_ppi;
+static struct clock_event_device __percpu *gt_evt;
+
+/*
+ * To get the value from the Global Timer Counter register proceed as follows:
+ * 1. Read the upper 32-bit timer counter register
+ * 2. Read the lower 32-bit timer counter register
+ * 3. Read the upper 32-bit timer counter register again. If the value is
+ * different to the 32-bit upper value read previously, go back to step 2.
+ * Otherwise the 64-bit timer counter value is correct.
+ */
+static u64 gt_counter_read(void)
+{
+ u64 counter;
+ u32 lower;
+ u32 upper, old_upper;
+
+ upper = readl_relaxed(gt_base + GT_COUNTER1);
+ do {
+ old_upper = upper;
+ lower = readl_relaxed(gt_base + GT_COUNTER0);
+ upper = readl_relaxed(gt_base + GT_COUNTER1);
+ } while (upper != old_upper);
+
+ counter = upper;
+ counter <<= 32;
+ counter |= lower;
+ return counter;
+}
+
+/**
+ * To ensure that updates to comparator value register do not set the
+ * Interrupt Status Register proceed as follows:
+ * 1. Clear the Comp Enable bit in the Timer Control Register.
+ * 2. Write the lower 32-bit Comparator Value Register.
+ * 3. Write the upper 32-bit Comparator Value Register.
+ * 4. Set the Comp Enable bit and, if necessary, the IRQ enable bit.
+ */
+static void gt_compare_set(unsigned long delta, int periodic)
+{
+ u64 counter = gt_counter_read();
+ unsigned long ctrl;
+
+ counter += delta;
+ ctrl = GT_CONTROL_TIMER_ENABLE;
+ writel(ctrl, gt_base + GT_CONTROL);
+ writel(lower_32_bits(counter), gt_base + GT_COMP0);
+ writel(upper_32_bits(counter), gt_base + GT_COMP1);
+
+ if (periodic) {
+ writel(delta, gt_base + GT_AUTO_INC);
+ ctrl |= GT_CONTROL_AUTO_INC;
+ }
+
+ ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
+ writel(ctrl, gt_base + GT_CONTROL);
+}
+
+static void gt_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ unsigned long ctrl;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ ctrl = readl(gt_base + GT_CONTROL);
+ ctrl &= ~(GT_CONTROL_COMP_ENABLE |
+ GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC);
+ writel(ctrl, gt_base + GT_CONTROL);
+ break;
+ default:
+ break;
+ }
+}
+
+static int gt_clockevent_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ gt_compare_set(evt, 0);
+ return 0;
+}
+
+static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ if (!(readl_relaxed(gt_base + GT_INT_STATUS) &
+ GT_INT_STATUS_EVENT_FLAG))
+ return IRQ_NONE;
+
+ /**
+ * ERRATA 740657( Global Timer can send 2 interrupts for
+ * the same event in single-shot mode)
+ * Workaround:
+ * Either disable single-shot mode.
+ * Or
+ * Modify the Interrupt Handler to avoid the
+ * offending sequence. This is achieved by clearing
+ * the Global Timer flag _after_ having incremented
+ * the Comparator register value to a higher value.
+ */
+ if (evt->mode == CLOCK_EVT_MODE_ONESHOT)
+ gt_compare_set(ULONG_MAX, 0);
+
+ writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
+{
+ int cpu = smp_processor_id();
+
+ clk->name = "arm_global_timer";
+ clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ clk->set_mode = gt_clockevent_set_mode;
+ clk->set_next_event = gt_clockevent_set_next_event;
+ clk->cpumask = cpumask_of(cpu);
+ clk->rating = 300;
+ clk->irq = gt_ppi;
+ clockevents_config_and_register(clk, gt_clk_rate,
+ 1, 0xffffffff);
+ enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
+ return 0;
+}
+
+static void gt_clockevents_stop(struct clock_event_device *clk)
+{
+ gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+ disable_percpu_irq(clk->irq);
+}
+
+static cycle_t gt_clocksource_read(struct clocksource *cs)
+{
+ return gt_counter_read();
+}
+
+static struct clocksource gt_clocksource = {
+ .name = "arm_global_timer",
+ .rating = 300,
+ .read = gt_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+static u32 notrace gt_sched_clock_read(void)
+{
+ return gt_counter_read();
+}
+#endif
+
+static void __init gt_clocksource_init(void)
+{
+ writel(0, gt_base + GT_CONTROL);
+ writel(0, gt_base + GT_COUNTER0);
+ writel(0, gt_base + GT_COUNTER1);
+ /* enables timer on all the cores */
+ writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ setup_sched_clock(gt_sched_clock_read, 32, gt_clk_rate);
+#endif
+ clocksource_register_hz(&gt_clocksource, gt_clk_rate);
+}
+
+static int __cpuinit gt_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ gt_clockevents_init(this_cpu_ptr(gt_evt));
+ break;
+ case CPU_DYING:
+ gt_clockevents_stop(this_cpu_ptr(gt_evt));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+static struct notifier_block gt_cpu_nb __cpuinitdata = {
+ .notifier_call = gt_cpu_notify,
+};
+
+static void __init global_timer_of_register(struct device_node *np)
+{
+ struct clk *gt_clk;
+ int err = 0;
+
+ /*
+ * In r2p0 the comparators for each processor with the global timer
+ * fire when the timer value is greater than or equal to. In previous
+ * revisions the comparators fired when the timer value was equal to.
+ */
+ if ((read_cpuid_id() & 0xf0000f) < 0x200000) {
+ pr_warn("global-timer: non support for this cpu version.\n");
+ return;
+ }
+
+ gt_ppi = irq_of_parse_and_map(np, 0);
+ if (!gt_ppi) {
+ pr_warn("global-timer: unable to parse irq\n");
+ return;
+ }
+
+ gt_base = of_iomap(np, 0);
+ if (!gt_base) {
+ pr_warn("global-timer: invalid base address\n");
+ return;
+ }
+
+ gt_clk = of_clk_get(np, 0);
+ if (!IS_ERR(gt_clk)) {
+ err = clk_prepare_enable(gt_clk);
+ if (err)
+ goto out_unmap;
+ } else {
+ pr_warn("global-timer: clk not found\n");
+ err = -EINVAL;
+ goto out_unmap;
+ }
+
+ gt_clk_rate = clk_get_rate(gt_clk);
+ gt_evt = alloc_percpu(struct clock_event_device);
+ if (!gt_evt) {
+ pr_warn("global-timer: can't allocate memory\n");
+ err = -ENOMEM;
+ goto out_clk;
+ }
+
+ err = request_percpu_irq(gt_ppi, gt_clockevent_interrupt,
+ "gt", gt_evt);
+ if (err) {
+ pr_warn("global-timer: can't register interrupt %d (%d)\n",
+ gt_ppi, err);
+ goto out_free;
+ }
+
+ err = register_cpu_notifier(&gt_cpu_nb);
+ if (err) {
+ pr_warn("global-timer: unable to register cpu notifier.\n");
+ goto out_irq;
+ }
+
+ /* Immediately configure the timer on the boot CPU */
+ gt_clocksource_init();
+ gt_clockevents_init(this_cpu_ptr(gt_evt));
+
+ return;
+
+out_irq:
+ free_percpu_irq(gt_ppi, gt_evt);
+out_free:
+ free_percpu(gt_evt);
+out_clk:
+ clk_disable_unprepare(gt_clk);
+out_unmap:
+ iounmap(gt_base);
+ WARN(err, "ARM Global timer register failed (%d)\n", err);
+}
+
+/* Only tested on r2p2 and r3p0 */
+CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer",
+ global_timer_of_register);
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
new file mode 100644
index 000000000000..ecbeb6810215
--- /dev/null
+++ b/drivers/clocksource/time-orion.c
@@ -0,0 +1,150 @@
+/*
+ * Marvell Orion SoC timer handling.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Timer 0 is used as free-running clocksource, while timer 1 is
+ * used as clock_event_device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <asm/sched_clock.h>
+
+#define TIMER_CTRL 0x00
+#define TIMER0_EN BIT(0)
+#define TIMER0_RELOAD_EN BIT(1)
+#define TIMER1_EN BIT(2)
+#define TIMER1_RELOAD_EN BIT(3)
+#define TIMER0_RELOAD 0x10
+#define TIMER0_VAL 0x14
+#define TIMER1_RELOAD 0x18
+#define TIMER1_VAL 0x1c
+
+#define ORION_ONESHOT_MIN 1
+#define ORION_ONESHOT_MAX 0xfffffffe
+
+static void __iomem *timer_base;
+static DEFINE_SPINLOCK(timer_ctrl_lock);
+
+/*
+ * Thread-safe access to TIMER_CTRL register
+ * (shared with watchdog timer)
+ */
+void orion_timer_ctrl_clrset(u32 clr, u32 set)
+{
+ spin_lock(&timer_ctrl_lock);
+ writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
+ timer_base + TIMER_CTRL);
+ spin_unlock(&timer_ctrl_lock);
+}
+EXPORT_SYMBOL(orion_timer_ctrl_clrset);
+
+/*
+ * Free-running clocksource handling.
+ */
+static u32 notrace orion_read_sched_clock(void)
+{
+ return ~readl(timer_base + TIMER0_VAL);
+}
+
+/*
+ * Clockevent handling.
+ */
+static u32 ticks_per_jiffy;
+
+static int orion_clkevt_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ /* setup and enable one-shot timer */
+ writel(delta, timer_base + TIMER1_VAL);
+ orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+
+ return 0;
+}
+
+static void orion_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ /* setup and enable periodic timer at 1/HZ intervals */
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
+ orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+ } else {
+ /* disable timer */
+ orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+ }
+}
+
+static struct clock_event_device orion_clkevt = {
+ .name = "orion_event",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 300,
+ .set_next_event = orion_clkevt_next_event,
+ .set_mode = orion_clkevt_mode,
+};
+
+static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
+{
+ orion_clkevt.event_handler(&orion_clkevt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction orion_clkevt_irq = {
+ .name = "orion_event",
+ .flags = IRQF_TIMER,
+ .handler = orion_clkevt_irq_handler,
+};
+
+static void __init orion_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+ int irq;
+
+ /* timer registers are shared with watchdog timer */
+ timer_base = of_iomap(np, 0);
+ if (!timer_base)
+ panic("%s: unable to map resource\n", np->name);
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ panic("%s: unable to get clk\n", np->name);
+ clk_prepare_enable(clk);
+
+ /* we are only interested in timer1 irq */
+ irq = irq_of_parse_and_map(np, 1);
+ if (irq <= 0)
+ panic("%s: unable to parse timer1 irq\n", np->name);
+
+ /* setup timer0 as free-running clocksource */
+ writel(~0, timer_base + TIMER0_VAL);
+ writel(~0, timer_base + TIMER0_RELOAD);
+ orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+ clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
+ clk_get_rate(clk), 300, 32,
+ clocksource_mmio_readl_down);
+ setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
+
+ /* setup timer1 as clockevent timer */
+ if (setup_irq(irq, &orion_clkevt_irq))
+ panic("%s: unable to setup irq\n", np->name);
+
+ ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
+ orion_clkevt.cpumask = cpumask_of(0);
+ orion_clkevt.irq = irq;
+ clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
+ ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 6a015ada5285..0937b8d6c2a4 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -312,11 +312,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
switch (state) {
case CPUFREQ_PRECHANGE:
- if (WARN(policy->transition_ongoing,
+ if (WARN(policy->transition_ongoing ==
+ cpumask_weight(policy->cpus),
"In middle of another frequency transition\n"))
return;
- policy->transition_ongoing = true;
+ policy->transition_ongoing++;
/* detect if the driver reported a value as "old frequency"
* which is not equal to what the cpufreq core thinks is
@@ -341,7 +342,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
"No frequency transition in progress\n"))
return;
- policy->transition_ongoing = false;
+ policy->transition_ongoing--;
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index a697a64d5383..878f09005fad 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -349,21 +349,21 @@ config EDAC_OCTEON_PC
config EDAC_OCTEON_L2C
tristate "Cavium Octeon Secondary Caches (L2C)"
- depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+ depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC
help
Support for error detection and correction on the
Cavium Octeon family of SOCs.
config EDAC_OCTEON_LMC
tristate "Cavium Octeon DRAM Memory Controller (LMC)"
- depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+ depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC
help
Support for error detection and correction on the
Cavium Octeon family of SOCs.
config EDAC_OCTEON_PCI
tristate "Cavium Octeon PCI Controller"
- depends on EDAC_MM_EDAC && PCI && CPU_CAVIUM_OCTEON
+ depends on EDAC_MM_EDAC && PCI && CAVIUM_OCTEON_SOC
help
Support for error detection and correction on the
Cavium Octeon family of SOCs.
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index a4f5ce14dc1c..271b42bbfb72 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -133,8 +133,8 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
},
};
-static u8 *edid_load(struct drm_connector *connector, char *name,
- char *connector_name)
+static u8 *edid_load(struct drm_connector *connector, const char *name,
+ const char *connector_name)
{
const struct firmware *fw;
struct platform_device *pdev;
@@ -242,7 +242,7 @@ out:
int drm_load_edid_firmware(struct drm_connector *connector)
{
- char *connector_name = drm_get_connector_name(connector);
+ const char *connector_name = drm_get_connector_name(connector);
char *edidname = edid_firmware, *last, *colon;
int ret;
struct edid *edid;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index fdc2ab4af315..dc6dea614abd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -739,7 +739,7 @@ config I2C_WMT
config I2C_OCTEON
tristate "Cavium OCTEON I2C bus support"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
help
Say yes if you want to support the I2C serial bus on Cavium
OCTEON SOC.
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
index 7e27d3295e55..300daabaa575 100644
--- a/drivers/ide/delkin_cb.c
+++ b/drivers/ide/delkin_cb.c
@@ -173,18 +173,7 @@ static struct pci_driver delkin_cb_pci_driver = {
.resume = delkin_cb_resume,
};
-static int __init delkin_cb_init(void)
-{
- return pci_register_driver(&delkin_cb_pci_driver);
-}
-
-static void __exit delkin_cb_exit(void)
-{
- pci_unregister_driver(&delkin_cb_pci_driver);
-}
-
-module_init(delkin_cb_init);
-module_exit(delkin_cb_exit);
+module_pci_driver(delkin_cb_pci_driver);
MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 51beb85250d4..0a8440ae0565 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -183,20 +183,7 @@ static struct platform_driver amiga_gayle_ide_driver = {
},
};
-static int __init amiga_gayle_ide_init(void)
-{
- return platform_driver_probe(&amiga_gayle_ide_driver,
- amiga_gayle_ide_probe);
-}
-
-module_init(amiga_gayle_ide_init);
-
-static void __exit amiga_gayle_ide_exit(void)
-{
- platform_driver_unregister(&amiga_gayle_ide_driver);
-}
-
-module_exit(amiga_gayle_ide_exit);
+module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-gayle-ide");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 729428edeba2..dabb88b1cbec 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -239,9 +239,6 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
int page_is_high;
- if (nr_bytes > PAGE_SIZE)
- nr_bytes = PAGE_SIZE;
-
page = sg_page(cursg);
offset = cursg->offset + cmd->cursg_ofs;
@@ -249,6 +246,8 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
+ nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset));
+
page_is_high = PageHighMem(page);
if (page_is_high)
local_irq_save(flags);
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index 91d49dd957ef..ede8575ac7d5 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -203,18 +203,7 @@ static struct platform_driver tx4938ide_driver = {
.remove = __exit_p(tx4938ide_remove),
};
-static int __init tx4938ide_init(void)
-{
- return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe);
-}
-
-static void __exit tx4938ide_exit(void)
-{
- platform_driver_unregister(&tx4938ide_driver);
-}
-
-module_init(tx4938ide_init);
-module_exit(tx4938ide_exit);
+module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe);
MODULE_DESCRIPTION("TX4938 internal IDE driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index c0ab800b7bb3..4ecdee5eca83 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -624,18 +624,7 @@ static struct platform_driver tx4939ide_driver = {
.resume = tx4939ide_resume,
};
-static int __init tx4939ide_init(void)
-{
- return platform_driver_probe(&tx4939ide_driver, tx4939ide_probe);
-}
-
-static void __exit tx4939ide_exit(void)
-{
- platform_driver_unregister(&tx4939ide_driver);
-}
-
-module_init(tx4939ide_init);
-module_exit(tx4939ide_exit);
+module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe);
MODULE_DESCRIPTION("TX4939 internal IDE driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index c85b56c28099..5ceda710f516 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -50,6 +50,7 @@ source "drivers/infiniband/hw/amso1100/Kconfig"
source "drivers/infiniband/hw/cxgb3/Kconfig"
source "drivers/infiniband/hw/cxgb4/Kconfig"
source "drivers/infiniband/hw/mlx4/Kconfig"
+source "drivers/infiniband/hw/mlx5/Kconfig"
source "drivers/infiniband/hw/nes/Kconfig"
source "drivers/infiniband/hw/ocrdma/Kconfig"
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index b126fefe0b1c..1fe69888515f 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
obj-$(CONFIG_INFINIBAND_CXGB4) += hw/cxgb4/
obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/
+obj-$(CONFIG_MLX5_INFINIBAND) += hw/mlx5/
obj-$(CONFIG_INFINIBAND_NES) += hw/nes/
obj-$(CONFIG_INFINIBAND_OCRDMA) += hw/ocrdma/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index eaec8d7a3b73..e90f2b2eabd7 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -45,6 +45,7 @@
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <rdma/ib_addr.h>
+#include <rdma/ib.h>
MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("IB Address Translation");
@@ -70,6 +71,21 @@ static LIST_HEAD(req_list);
static DECLARE_DELAYED_WORK(work, process_req);
static struct workqueue_struct *addr_wq;
+int rdma_addr_size(struct sockaddr *addr)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_IB:
+ return sizeof(struct sockaddr_ib);
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL(rdma_addr_size);
+
void rdma_addr_register_client(struct rdma_addr_client *client)
{
atomic_set(&client->refcount, 1);
@@ -369,12 +385,12 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
goto err;
}
- memcpy(src_in, src_addr, ip_addr_size(src_addr));
+ memcpy(src_in, src_addr, rdma_addr_size(src_addr));
} else {
src_in->sa_family = dst_addr->sa_family;
}
- memcpy(dst_in, dst_addr, ip_addr_size(dst_addr));
+ memcpy(dst_in, dst_addr, rdma_addr_size(dst_addr));
req->addr = addr;
req->callback = callback;
req->context = context;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 34fbc2f60a09..f1c279fabe64 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -50,6 +50,7 @@
#include <rdma/rdma_cm.h>
#include <rdma/rdma_cm_ib.h>
#include <rdma/rdma_netlink.h>
+#include <rdma/ib.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_cm.h>
#include <rdma/ib_sa.h>
@@ -79,7 +80,6 @@ static LIST_HEAD(dev_list);
static LIST_HEAD(listen_any_list);
static DEFINE_MUTEX(lock);
static struct workqueue_struct *cma_wq;
-static DEFINE_IDR(sdp_ps);
static DEFINE_IDR(tcp_ps);
static DEFINE_IDR(udp_ps);
static DEFINE_IDR(ipoib_ps);
@@ -195,24 +195,7 @@ struct cma_hdr {
union cma_ip_addr dst_addr;
};
-struct sdp_hh {
- u8 bsdh[16];
- u8 sdp_version; /* Major version: 7:4 */
- u8 ip_version; /* IP version: 7:4 */
- u8 sdp_specific1[10];
- __be16 port;
- __be16 sdp_specific2;
- union cma_ip_addr src_addr;
- union cma_ip_addr dst_addr;
-};
-
-struct sdp_hah {
- u8 bsdh[16];
- u8 sdp_version;
-};
-
#define CMA_VERSION 0x00
-#define SDP_MAJ_VERSION 0x2
static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
{
@@ -261,21 +244,6 @@ static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
}
-static inline u8 sdp_get_majv(u8 sdp_version)
-{
- return sdp_version >> 4;
-}
-
-static inline u8 sdp_get_ip_ver(struct sdp_hh *hh)
-{
- return hh->ip_version >> 4;
-}
-
-static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
-{
- hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
-}
-
static void cma_attach_to_dev(struct rdma_id_private *id_priv,
struct cma_device *cma_dev)
{
@@ -310,16 +278,40 @@ static void cma_release_dev(struct rdma_id_private *id_priv)
mutex_unlock(&lock);
}
-static int cma_set_qkey(struct rdma_id_private *id_priv)
+static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv)
+{
+ return (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+}
+
+static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv)
+{
+ return (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
+}
+
+static inline unsigned short cma_family(struct rdma_id_private *id_priv)
+{
+ return id_priv->id.route.addr.src_addr.ss_family;
+}
+
+static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey)
{
struct ib_sa_mcmember_rec rec;
int ret = 0;
- if (id_priv->qkey)
+ if (id_priv->qkey) {
+ if (qkey && id_priv->qkey != qkey)
+ return -EINVAL;
+ return 0;
+ }
+
+ if (qkey) {
+ id_priv->qkey = qkey;
return 0;
+ }
switch (id_priv->id.ps) {
case RDMA_PS_UDP:
+ case RDMA_PS_IB:
id_priv->qkey = RDMA_UDP_QKEY;
break;
case RDMA_PS_IPOIB:
@@ -358,6 +350,27 @@ static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_nu
return -EADDRNOTAVAIL;
}
+static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr)
+{
+ dev_addr->dev_type = ARPHRD_INFINIBAND;
+ rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr);
+ ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey));
+}
+
+static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
+{
+ int ret;
+
+ if (addr->sa_family != AF_IB) {
+ ret = rdma_translate_ip(addr, dev_addr);
+ } else {
+ cma_translate_ib((struct sockaddr_ib *) addr, dev_addr);
+ ret = 0;
+ }
+
+ return ret;
+}
+
static int cma_acquire_dev(struct rdma_id_private *id_priv)
{
struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
@@ -401,6 +414,61 @@ out:
return ret;
}
+/*
+ * Select the source IB device and address to reach the destination IB address.
+ */
+static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
+{
+ struct cma_device *cma_dev, *cur_dev;
+ struct sockaddr_ib *addr;
+ union ib_gid gid, sgid, *dgid;
+ u16 pkey, index;
+ u8 port, p;
+ int i;
+
+ cma_dev = NULL;
+ addr = (struct sockaddr_ib *) cma_dst_addr(id_priv);
+ dgid = (union ib_gid *) &addr->sib_addr;
+ pkey = ntohs(addr->sib_pkey);
+
+ list_for_each_entry(cur_dev, &dev_list, list) {
+ if (rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+ continue;
+
+ for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+ if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
+ continue;
+
+ for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i, &gid); i++) {
+ if (!memcmp(&gid, dgid, sizeof(gid))) {
+ cma_dev = cur_dev;
+ sgid = gid;
+ port = p;
+ goto found;
+ }
+
+ if (!cma_dev && (gid.global.subnet_prefix ==
+ dgid->global.subnet_prefix)) {
+ cma_dev = cur_dev;
+ sgid = gid;
+ port = p;
+ }
+ }
+ }
+ }
+
+ if (!cma_dev)
+ return -ENODEV;
+
+found:
+ cma_attach_to_dev(id_priv, cma_dev);
+ id_priv->id.port_num = port;
+ addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
+ memcpy(&addr->sib_addr, &sgid, sizeof sgid);
+ cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
+ return 0;
+}
+
static void cma_deref_id(struct rdma_id_private *id_priv)
{
if (atomic_dec_and_test(&id_priv->refcount))
@@ -630,7 +698,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
if (id_priv->id.qp_type == IB_QPT_UD) {
- ret = cma_set_qkey(id_priv);
+ ret = cma_set_qkey(id_priv, 0);
if (ret)
return ret;
@@ -679,26 +747,30 @@ EXPORT_SYMBOL(rdma_init_qp_attr);
static inline int cma_zero_addr(struct sockaddr *addr)
{
- struct in6_addr *ip6;
-
- if (addr->sa_family == AF_INET)
- return ipv4_is_zeronet(
- ((struct sockaddr_in *)addr)->sin_addr.s_addr);
- else {
- ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
- return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
- ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
+ switch (addr->sa_family) {
+ case AF_INET:
+ return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr);
+ case AF_INET6:
+ return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr);
+ case AF_IB:
+ return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr);
+ default:
+ return 0;
}
}
static inline int cma_loopback_addr(struct sockaddr *addr)
{
- if (addr->sa_family == AF_INET)
- return ipv4_is_loopback(
- ((struct sockaddr_in *) addr)->sin_addr.s_addr);
- else
- return ipv6_addr_loopback(
- &((struct sockaddr_in6 *) addr)->sin6_addr);
+ switch (addr->sa_family) {
+ case AF_INET:
+ return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+ case AF_INET6:
+ return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr);
+ case AF_IB:
+ return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr);
+ default:
+ return 0;
+ }
}
static inline int cma_any_addr(struct sockaddr *addr)
@@ -715,18 +787,31 @@ static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
case AF_INET:
return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
((struct sockaddr_in *) dst)->sin_addr.s_addr;
- default:
+ case AF_INET6:
return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
&((struct sockaddr_in6 *) dst)->sin6_addr);
+ default:
+ return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,
+ &((struct sockaddr_ib *) dst)->sib_addr);
}
}
-static inline __be16 cma_port(struct sockaddr *addr)
+static __be16 cma_port(struct sockaddr *addr)
{
- if (addr->sa_family == AF_INET)
+ struct sockaddr_ib *sib;
+
+ switch (addr->sa_family) {
+ case AF_INET:
return ((struct sockaddr_in *) addr)->sin_port;
- else
+ case AF_INET6:
return ((struct sockaddr_in6 *) addr)->sin6_port;
+ case AF_IB:
+ sib = (struct sockaddr_ib *) addr;
+ return htons((u16) (be64_to_cpu(sib->sib_sid) &
+ be64_to_cpu(sib->sib_sid_mask)));
+ default:
+ return 0;
+ }
}
static inline int cma_any_port(struct sockaddr *addr)
@@ -734,83 +819,92 @@ static inline int cma_any_port(struct sockaddr *addr)
return !cma_port(addr);
}
-static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
- u8 *ip_ver, __be16 *port,
- union cma_ip_addr **src, union cma_ip_addr **dst)
+static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+ struct ib_sa_path_rec *path)
{
- switch (ps) {
- case RDMA_PS_SDP:
- if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) !=
- SDP_MAJ_VERSION)
- return -EINVAL;
+ struct sockaddr_ib *listen_ib, *ib;
- *ip_ver = sdp_get_ip_ver(hdr);
- *port = ((struct sdp_hh *) hdr)->port;
- *src = &((struct sdp_hh *) hdr)->src_addr;
- *dst = &((struct sdp_hh *) hdr)->dst_addr;
- break;
- default:
- if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION)
- return -EINVAL;
+ listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
+ ib = (struct sockaddr_ib *) &id->route.addr.src_addr;
+ ib->sib_family = listen_ib->sib_family;
+ ib->sib_pkey = path->pkey;
+ ib->sib_flowinfo = path->flow_label;
+ memcpy(&ib->sib_addr, &path->sgid, 16);
+ ib->sib_sid = listen_ib->sib_sid;
+ ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
+ ib->sib_scope_id = listen_ib->sib_scope_id;
- *ip_ver = cma_get_ip_ver(hdr);
- *port = ((struct cma_hdr *) hdr)->port;
- *src = &((struct cma_hdr *) hdr)->src_addr;
- *dst = &((struct cma_hdr *) hdr)->dst_addr;
- break;
- }
-
- if (*ip_ver != 4 && *ip_ver != 6)
- return -EINVAL;
- return 0;
+ ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
+ ib->sib_family = listen_ib->sib_family;
+ ib->sib_pkey = path->pkey;
+ ib->sib_flowinfo = path->flow_label;
+ memcpy(&ib->sib_addr, &path->dgid, 16);
}
-static void cma_save_net_info(struct rdma_addr *addr,
- struct rdma_addr *listen_addr,
- u8 ip_ver, __be16 port,
- union cma_ip_addr *src, union cma_ip_addr *dst)
+static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+ struct cma_hdr *hdr)
{
struct sockaddr_in *listen4, *ip4;
+
+ listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr;
+ ip4 = (struct sockaddr_in *) &id->route.addr.src_addr;
+ ip4->sin_family = listen4->sin_family;
+ ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
+ ip4->sin_port = listen4->sin_port;
+
+ ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr;
+ ip4->sin_family = listen4->sin_family;
+ ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
+ ip4->sin_port = hdr->port;
+}
+
+static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+ struct cma_hdr *hdr)
+{
struct sockaddr_in6 *listen6, *ip6;
- switch (ip_ver) {
+ listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr;
+ ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr;
+ ip6->sin6_family = listen6->sin6_family;
+ ip6->sin6_addr = hdr->dst_addr.ip6;
+ ip6->sin6_port = listen6->sin6_port;
+
+ ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr;
+ ip6->sin6_family = listen6->sin6_family;
+ ip6->sin6_addr = hdr->src_addr.ip6;
+ ip6->sin6_port = hdr->port;
+}
+
+static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+ struct ib_cm_event *ib_event)
+{
+ struct cma_hdr *hdr;
+
+ if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+ cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
+ return 0;
+ }
+
+ hdr = ib_event->private_data;
+ if (hdr->cma_version != CMA_VERSION)
+ return -EINVAL;
+
+ switch (cma_get_ip_ver(hdr)) {
case 4:
- listen4 = (struct sockaddr_in *) &listen_addr->src_addr;
- ip4 = (struct sockaddr_in *) &addr->src_addr;
- ip4->sin_family = listen4->sin_family;
- ip4->sin_addr.s_addr = dst->ip4.addr;
- ip4->sin_port = listen4->sin_port;
-
- ip4 = (struct sockaddr_in *) &addr->dst_addr;
- ip4->sin_family = listen4->sin_family;
- ip4->sin_addr.s_addr = src->ip4.addr;
- ip4->sin_port = port;
+ cma_save_ip4_info(id, listen_id, hdr);
break;
case 6:
- listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr;
- ip6 = (struct sockaddr_in6 *) &addr->src_addr;
- ip6->sin6_family = listen6->sin6_family;
- ip6->sin6_addr = dst->ip6;
- ip6->sin6_port = listen6->sin6_port;
-
- ip6 = (struct sockaddr_in6 *) &addr->dst_addr;
- ip6->sin6_family = listen6->sin6_family;
- ip6->sin6_addr = src->ip6;
- ip6->sin6_port = port;
+ cma_save_ip6_info(id, listen_id, hdr);
break;
default:
- break;
+ return -EINVAL;
}
+ return 0;
}
-static inline int cma_user_data_offset(enum rdma_port_space ps)
+static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
{
- switch (ps) {
- case RDMA_PS_SDP:
- return 0;
- default:
- return sizeof(struct cma_hdr);
- }
+ return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
}
static void cma_cancel_route(struct rdma_id_private *id_priv)
@@ -861,8 +955,7 @@ static void cma_cancel_operation(struct rdma_id_private *id_priv,
cma_cancel_route(id_priv);
break;
case RDMA_CM_LISTEN:
- if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
- && !id_priv->cma_dev)
+ if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev)
cma_cancel_listens(id_priv);
break;
default:
@@ -977,16 +1070,6 @@ reject:
return ret;
}
-static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
-{
- if (id_priv->id.ps == RDMA_PS_SDP &&
- sdp_get_majv(((struct sdp_hah *) data)->sdp_version) !=
- SDP_MAJ_VERSION)
- return -EINVAL;
-
- return 0;
-}
-
static void cma_set_rep_event_data(struct rdma_cm_event *event,
struct ib_cm_rep_event_param *rep_data,
void *private_data)
@@ -1021,15 +1104,13 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
event.status = -ETIMEDOUT;
break;
case IB_CM_REP_RECEIVED:
- event.status = cma_verify_rep(id_priv, ib_event->private_data);
- if (event.status)
- event.event = RDMA_CM_EVENT_CONNECT_ERROR;
- else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
+ if (id_priv->id.qp) {
event.status = cma_rep_recv(id_priv);
event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
RDMA_CM_EVENT_ESTABLISHED;
- } else
+ } else {
event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
+ }
cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
ib_event->private_data);
break;
@@ -1085,22 +1166,16 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
struct rdma_id_private *id_priv;
struct rdma_cm_id *id;
struct rdma_route *rt;
- union cma_ip_addr *src, *dst;
- __be16 port;
- u8 ip_ver;
int ret;
- if (cma_get_net_info(ib_event->private_data, listen_id->ps,
- &ip_ver, &port, &src, &dst))
- return NULL;
-
id = rdma_create_id(listen_id->event_handler, listen_id->context,
listen_id->ps, ib_event->param.req_rcvd.qp_type);
if (IS_ERR(id))
return NULL;
- cma_save_net_info(&id->route.addr, &listen_id->route.addr,
- ip_ver, port, src, dst);
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (cma_save_net_info(id, listen_id, ib_event))
+ goto err;
rt = &id->route;
rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
@@ -1113,19 +1188,17 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
if (rt->num_paths == 2)
rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
- if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
+ if (cma_any_addr(cma_src_addr(id_priv))) {
rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
} else {
- ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
- &rt->addr.dev_addr);
+ ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
if (ret)
goto err;
}
rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
- id_priv = container_of(id, struct rdma_id_private, id);
id_priv->state = RDMA_CM_CONNECT;
return id_priv;
@@ -1139,9 +1212,6 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
{
struct rdma_id_private *id_priv;
struct rdma_cm_id *id;
- union cma_ip_addr *src, *dst;
- __be16 port;
- u8 ip_ver;
int ret;
id = rdma_create_id(listen_id->event_handler, listen_id->context,
@@ -1149,22 +1219,16 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
if (IS_ERR(id))
return NULL;
-
- if (cma_get_net_info(ib_event->private_data, listen_id->ps,
- &ip_ver, &port, &src, &dst))
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (cma_save_net_info(id, listen_id, ib_event))
goto err;
- cma_save_net_info(&id->route.addr, &listen_id->route.addr,
- ip_ver, port, src, dst);
-
if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
- ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
- &id->route.addr.dev_addr);
+ ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr);
if (ret)
goto err;
}
- id_priv = container_of(id, struct rdma_id_private, id);
id_priv->state = RDMA_CM_CONNECT;
return id_priv;
err:
@@ -1210,7 +1274,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
return -ECONNABORTED;
memset(&event, 0, sizeof event);
- offset = cma_user_data_offset(listen_id->id.ps);
+ offset = cma_user_data_offset(listen_id);
event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
conn_id = cma_new_udp_id(&listen_id->id, ib_event);
@@ -1272,58 +1336,44 @@ err1:
return ret;
}
-static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
+__be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr)
{
- return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr)));
+ if (addr->sa_family == AF_IB)
+ return ((struct sockaddr_ib *) addr)->sib_sid;
+
+ return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr)));
}
+EXPORT_SYMBOL(rdma_get_service_id);
static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
struct ib_cm_compare_data *compare)
{
struct cma_hdr *cma_data, *cma_mask;
- struct sdp_hh *sdp_data, *sdp_mask;
__be32 ip4_addr;
struct in6_addr ip6_addr;
memset(compare, 0, sizeof *compare);
cma_data = (void *) compare->data;
cma_mask = (void *) compare->mask;
- sdp_data = (void *) compare->data;
- sdp_mask = (void *) compare->mask;
switch (addr->sa_family) {
case AF_INET:
ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
- if (ps == RDMA_PS_SDP) {
- sdp_set_ip_ver(sdp_data, 4);
- sdp_set_ip_ver(sdp_mask, 0xF);
- sdp_data->dst_addr.ip4.addr = ip4_addr;
- sdp_mask->dst_addr.ip4.addr = htonl(~0);
- } else {
- cma_set_ip_ver(cma_data, 4);
- cma_set_ip_ver(cma_mask, 0xF);
- if (!cma_any_addr(addr)) {
- cma_data->dst_addr.ip4.addr = ip4_addr;
- cma_mask->dst_addr.ip4.addr = htonl(~0);
- }
+ cma_set_ip_ver(cma_data, 4);
+ cma_set_ip_ver(cma_mask, 0xF);
+ if (!cma_any_addr(addr)) {
+ cma_data->dst_addr.ip4.addr = ip4_addr;
+ cma_mask->dst_addr.ip4.addr = htonl(~0);
}
break;
case AF_INET6:
ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
- if (ps == RDMA_PS_SDP) {
- sdp_set_ip_ver(sdp_data, 6);
- sdp_set_ip_ver(sdp_mask, 0xF);
- sdp_data->dst_addr.ip6 = ip6_addr;
- memset(&sdp_mask->dst_addr.ip6, 0xFF,
- sizeof sdp_mask->dst_addr.ip6);
- } else {
- cma_set_ip_ver(cma_data, 6);
- cma_set_ip_ver(cma_mask, 0xF);
- if (!cma_any_addr(addr)) {
- cma_data->dst_addr.ip6 = ip6_addr;
- memset(&cma_mask->dst_addr.ip6, 0xFF,
- sizeof cma_mask->dst_addr.ip6);
- }
+ cma_set_ip_ver(cma_data, 6);
+ cma_set_ip_ver(cma_mask, 0xF);
+ if (!cma_any_addr(addr)) {
+ cma_data->dst_addr.ip6 = ip6_addr;
+ memset(&cma_mask->dst_addr.ip6, 0xFF,
+ sizeof cma_mask->dst_addr.ip6);
}
break;
default:
@@ -1347,9 +1397,9 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
event.event = RDMA_CM_EVENT_DISCONNECTED;
break;
case IW_CM_EVENT_CONNECT_REPLY:
- sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ sin = (struct sockaddr_in *) cma_src_addr(id_priv);
*sin = iw_event->local_addr;
- sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
+ sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
*sin = iw_event->remote_addr;
switch (iw_event->status) {
case 0:
@@ -1447,9 +1497,9 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
cm_id->context = conn_id;
cm_id->cm_handler = cma_iw_handler;
- sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
+ sin = (struct sockaddr_in *) cma_src_addr(conn_id);
*sin = iw_event->local_addr;
- sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
+ sin = (struct sockaddr_in *) cma_dst_addr(conn_id);
*sin = iw_event->remote_addr;
ret = ib_query_device(conn_id->id.device, &attr);
@@ -1506,8 +1556,8 @@ static int cma_ib_listen(struct rdma_id_private *id_priv)
id_priv->cm_id.ib = id;
- addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
- svc_id = cma_get_service_id(id_priv->id.ps, addr);
+ addr = cma_src_addr(id_priv);
+ svc_id = rdma_get_service_id(&id_priv->id, addr);
if (cma_any_addr(addr) && !id_priv->afonly)
ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL);
else {
@@ -1537,7 +1587,7 @@ static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
id_priv->cm_id.iw = id;
- sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ sin = (struct sockaddr_in *) cma_src_addr(id_priv);
id_priv->cm_id.iw->local_addr = *sin;
ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
@@ -1567,6 +1617,10 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
struct rdma_cm_id *id;
int ret;
+ if (cma_family(id_priv) == AF_IB &&
+ rdma_node_get_transport(cma_dev->device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
id_priv->id.qp_type);
if (IS_ERR(id))
@@ -1575,8 +1629,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
dev_id_priv = container_of(id, struct rdma_id_private, id);
dev_id_priv->state = RDMA_CM_ADDR_BOUND;
- memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
- ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+ memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
+ rdma_addr_size(cma_src_addr(id_priv)));
cma_attach_to_dev(dev_id_priv, cma_dev);
list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
@@ -1634,31 +1688,39 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct cma_work *work)
{
- struct rdma_addr *addr = &id_priv->id.route.addr;
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
struct ib_sa_path_rec path_rec;
ib_sa_comp_mask comp_mask;
struct sockaddr_in6 *sin6;
+ struct sockaddr_ib *sib;
memset(&path_rec, 0, sizeof path_rec);
- rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
- rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
- path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
+ rdma_addr_get_sgid(dev_addr, &path_rec.sgid);
+ rdma_addr_get_dgid(dev_addr, &path_rec.dgid);
+ path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
path_rec.numb_path = 1;
path_rec.reversible = 1;
- path_rec.service_id = cma_get_service_id(id_priv->id.ps,
- (struct sockaddr *) &addr->dst_addr);
+ path_rec.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
- if (addr->src_addr.ss_family == AF_INET) {
+ switch (cma_family(id_priv)) {
+ case AF_INET:
path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
- } else {
- sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+ break;
+ case AF_IB:
+ sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+ path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20);
+ comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+ break;
}
id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
@@ -1800,14 +1862,9 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
struct rdma_addr *addr = &route->addr;
struct cma_work *work;
int ret;
- struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
- struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
struct net_device *ndev = NULL;
u16 vid;
- if (src_addr->sin_family != dst_addr->sin_family)
- return -EINVAL;
-
work = kzalloc(sizeof *work, GFP_KERNEL);
if (!work)
return -ENOMEM;
@@ -1913,28 +1970,57 @@ err:
}
EXPORT_SYMBOL(rdma_resolve_route);
+static void cma_set_loopback(struct sockaddr *addr)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ break;
+ case AF_INET6:
+ ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr,
+ 0, 0, 0, htonl(1));
+ break;
+ default:
+ ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr,
+ 0, 0, 0, htonl(1));
+ break;
+ }
+}
+
static int cma_bind_loopback(struct rdma_id_private *id_priv)
{
- struct cma_device *cma_dev;
+ struct cma_device *cma_dev, *cur_dev;
struct ib_port_attr port_attr;
union ib_gid gid;
u16 pkey;
int ret;
u8 p;
+ cma_dev = NULL;
mutex_lock(&lock);
- if (list_empty(&dev_list)) {
+ list_for_each_entry(cur_dev, &dev_list, list) {
+ if (cma_family(id_priv) == AF_IB &&
+ rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+ continue;
+
+ if (!cma_dev)
+ cma_dev = cur_dev;
+
+ for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+ if (!ib_query_port(cur_dev->device, p, &port_attr) &&
+ port_attr.state == IB_PORT_ACTIVE) {
+ cma_dev = cur_dev;
+ goto port_found;
+ }
+ }
+ }
+
+ if (!cma_dev) {
ret = -ENODEV;
goto out;
}
- list_for_each_entry(cma_dev, &dev_list, list)
- for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p)
- if (!ib_query_port(cma_dev->device, p, &port_attr) &&
- port_attr.state == IB_PORT_ACTIVE)
- goto port_found;
p = 1;
- cma_dev = list_entry(dev_list.next, struct cma_device, list);
port_found:
ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
@@ -1953,6 +2039,7 @@ port_found:
ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
id_priv->id.port_num = p;
cma_attach_to_dev(id_priv, cma_dev);
+ cma_set_loopback(cma_src_addr(id_priv));
out:
mutex_unlock(&lock);
return ret;
@@ -1980,8 +2067,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
event.event = RDMA_CM_EVENT_ADDR_ERROR;
event.status = status;
} else {
- memcpy(&id_priv->id.route.addr.src_addr, src_addr,
- ip_addr_size(src_addr));
+ memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
}
@@ -2000,7 +2086,6 @@ out:
static int cma_resolve_loopback(struct rdma_id_private *id_priv)
{
struct cma_work *work;
- struct sockaddr *src, *dst;
union ib_gid gid;
int ret;
@@ -2017,18 +2102,36 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
- src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
- if (cma_zero_addr(src)) {
- dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
- if ((src->sa_family = dst->sa_family) == AF_INET) {
- ((struct sockaddr_in *)src)->sin_addr =
- ((struct sockaddr_in *)dst)->sin_addr;
- } else {
- ((struct sockaddr_in6 *)src)->sin6_addr =
- ((struct sockaddr_in6 *)dst)->sin6_addr;
- }
+ work->id = id_priv;
+ INIT_WORK(&work->work, cma_work_handler);
+ work->old_state = RDMA_CM_ADDR_QUERY;
+ work->new_state = RDMA_CM_ADDR_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ queue_work(cma_wq, &work->work);
+ return 0;
+err:
+ kfree(work);
+ return ret;
+}
+
+static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
+{
+ struct cma_work *work;
+ int ret;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ if (!id_priv->cma_dev) {
+ ret = cma_resolve_ib_dev(id_priv);
+ if (ret)
+ goto err;
}
+ rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
+ &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
+
work->id = id_priv;
INIT_WORK(&work->work, cma_work_handler);
work->old_state = RDMA_CM_ADDR_QUERY;
@@ -2046,9 +2149,13 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
{
if (!src_addr || !src_addr->sa_family) {
src_addr = (struct sockaddr *) &id->route.addr.src_addr;
- if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
+ src_addr->sa_family = dst_addr->sa_family;
+ if (dst_addr->sa_family == AF_INET6) {
((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
+ } else if (dst_addr->sa_family == AF_IB) {
+ ((struct sockaddr_ib *) src_addr)->sib_pkey =
+ ((struct sockaddr_ib *) dst_addr)->sib_pkey;
}
}
return rdma_bind_addr(id, src_addr);
@@ -2067,17 +2174,25 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
return ret;
}
+ if (cma_family(id_priv) != dst_addr->sa_family)
+ return -EINVAL;
+
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
return -EINVAL;
atomic_inc(&id_priv->refcount);
- memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
- if (cma_any_addr(dst_addr))
+ memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
+ if (cma_any_addr(dst_addr)) {
ret = cma_resolve_loopback(id_priv);
- else
- ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr,
- dst_addr, &id->route.addr.dev_addr,
- timeout_ms, addr_handler, id_priv);
+ } else {
+ if (dst_addr->sa_family == AF_IB) {
+ ret = cma_resolve_ib_addr(id_priv);
+ } else {
+ ret = rdma_resolve_ip(&addr_client, cma_src_addr(id_priv),
+ dst_addr, &id->route.addr.dev_addr,
+ timeout_ms, addr_handler, id_priv);
+ }
+ }
if (ret)
goto err;
@@ -2097,7 +2212,7 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
id_priv = container_of(id, struct rdma_id_private, id);
spin_lock_irqsave(&id_priv->lock, flags);
- if (id_priv->state == RDMA_CM_IDLE) {
+ if (reuse || id_priv->state == RDMA_CM_IDLE) {
id_priv->reuseaddr = reuse;
ret = 0;
} else {
@@ -2131,10 +2246,29 @@ EXPORT_SYMBOL(rdma_set_afonly);
static void cma_bind_port(struct rdma_bind_list *bind_list,
struct rdma_id_private *id_priv)
{
- struct sockaddr_in *sin;
+ struct sockaddr *addr;
+ struct sockaddr_ib *sib;
+ u64 sid, mask;
+ __be16 port;
- sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
- sin->sin_port = htons(bind_list->port);
+ addr = cma_src_addr(id_priv);
+ port = htons(bind_list->port);
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *) addr)->sin_port = port;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) addr)->sin6_port = port;
+ break;
+ case AF_IB:
+ sib = (struct sockaddr_ib *) addr;
+ sid = be64_to_cpu(sib->sib_sid);
+ mask = be64_to_cpu(sib->sib_sid_mask);
+ sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port));
+ sib->sib_sid_mask = cpu_to_be64(~0ULL);
+ break;
+ }
id_priv->bind_list = bind_list;
hlist_add_head(&id_priv->node, &bind_list->owners);
}
@@ -2205,7 +2339,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
struct rdma_id_private *cur_id;
struct sockaddr *addr, *cur_addr;
- addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+ addr = cma_src_addr(id_priv);
hlist_for_each_entry(cur_id, &bind_list->owners, node) {
if (id_priv == cur_id)
continue;
@@ -2214,7 +2348,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
cur_id->reuseaddr)
continue;
- cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
+ cur_addr = cma_src_addr(cur_id);
if (id_priv->afonly && cur_id->afonly &&
(addr->sa_family != cur_addr->sa_family))
continue;
@@ -2234,7 +2368,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
unsigned short snum;
int ret;
- snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+ snum = ntohs(cma_port(cma_src_addr(id_priv)));
if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
@@ -2261,33 +2395,67 @@ static int cma_bind_listen(struct rdma_id_private *id_priv)
return ret;
}
-static int cma_get_port(struct rdma_id_private *id_priv)
+static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv)
{
- struct idr *ps;
- int ret;
-
switch (id_priv->id.ps) {
- case RDMA_PS_SDP:
- ps = &sdp_ps;
- break;
case RDMA_PS_TCP:
- ps = &tcp_ps;
- break;
+ return &tcp_ps;
case RDMA_PS_UDP:
- ps = &udp_ps;
- break;
+ return &udp_ps;
case RDMA_PS_IPOIB:
- ps = &ipoib_ps;
- break;
+ return &ipoib_ps;
case RDMA_PS_IB:
- ps = &ib_ps;
- break;
+ return &ib_ps;
default:
- return -EPROTONOSUPPORT;
+ return NULL;
+ }
+}
+
+static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv)
+{
+ struct idr *ps = NULL;
+ struct sockaddr_ib *sib;
+ u64 sid_ps, mask, sid;
+
+ sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+ mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK;
+ sid = be64_to_cpu(sib->sib_sid) & mask;
+
+ if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) {
+ sid_ps = RDMA_IB_IP_PS_IB;
+ ps = &ib_ps;
+ } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) &&
+ (sid == (RDMA_IB_IP_PS_TCP & mask))) {
+ sid_ps = RDMA_IB_IP_PS_TCP;
+ ps = &tcp_ps;
+ } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) &&
+ (sid == (RDMA_IB_IP_PS_UDP & mask))) {
+ sid_ps = RDMA_IB_IP_PS_UDP;
+ ps = &udp_ps;
}
+ if (ps) {
+ sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib)));
+ sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK |
+ be64_to_cpu(sib->sib_sid_mask));
+ }
+ return ps;
+}
+
+static int cma_get_port(struct rdma_id_private *id_priv)
+{
+ struct idr *ps;
+ int ret;
+
+ if (cma_family(id_priv) != AF_IB)
+ ps = cma_select_inet_ps(id_priv);
+ else
+ ps = cma_select_ib_ps(id_priv);
+ if (!ps)
+ return -EPROTONOSUPPORT;
+
mutex_lock(&lock);
- if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr))
+ if (cma_any_port(cma_src_addr(id_priv)))
ret = cma_alloc_any_port(ps, id_priv);
else
ret = cma_use_port(ps, id_priv);
@@ -2322,8 +2490,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
id_priv = container_of(id, struct rdma_id_private, id);
if (id_priv->state == RDMA_CM_IDLE) {
- ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
- ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
+ id->route.addr.src_addr.ss_family = AF_INET;
+ ret = rdma_bind_addr(id, cma_src_addr(id_priv));
if (ret)
return ret;
}
@@ -2370,7 +2538,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
struct rdma_id_private *id_priv;
int ret;
- if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
+ if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
+ addr->sa_family != AF_IB)
return -EAFNOSUPPORT;
id_priv = container_of(id, struct rdma_id_private, id);
@@ -2382,7 +2551,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
goto err1;
if (!cma_any_addr(addr)) {
- ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
+ ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
if (ret)
goto err1;
@@ -2391,7 +2560,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
goto err1;
}
- memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
+ memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
if (addr->sa_family == AF_INET)
id_priv->afonly = 1;
@@ -2414,62 +2583,32 @@ err1:
}
EXPORT_SYMBOL(rdma_bind_addr);
-static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
- struct rdma_route *route)
+static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
{
struct cma_hdr *cma_hdr;
- struct sdp_hh *sdp_hdr;
- if (route->addr.src_addr.ss_family == AF_INET) {
+ cma_hdr = hdr;
+ cma_hdr->cma_version = CMA_VERSION;
+ if (cma_family(id_priv) == AF_INET) {
struct sockaddr_in *src4, *dst4;
- src4 = (struct sockaddr_in *) &route->addr.src_addr;
- dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
-
- switch (ps) {
- case RDMA_PS_SDP:
- sdp_hdr = hdr;
- if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
- return -EINVAL;
- sdp_set_ip_ver(sdp_hdr, 4);
- sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
- sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
- sdp_hdr->port = src4->sin_port;
- break;
- default:
- cma_hdr = hdr;
- cma_hdr->cma_version = CMA_VERSION;
- cma_set_ip_ver(cma_hdr, 4);
- cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
- cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
- cma_hdr->port = src4->sin_port;
- break;
- }
- } else {
+ src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
+ dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
+
+ cma_set_ip_ver(cma_hdr, 4);
+ cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+ cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+ cma_hdr->port = src4->sin_port;
+ } else if (cma_family(id_priv) == AF_INET6) {
struct sockaddr_in6 *src6, *dst6;
- src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
- dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
-
- switch (ps) {
- case RDMA_PS_SDP:
- sdp_hdr = hdr;
- if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
- return -EINVAL;
- sdp_set_ip_ver(sdp_hdr, 6);
- sdp_hdr->src_addr.ip6 = src6->sin6_addr;
- sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
- sdp_hdr->port = src6->sin6_port;
- break;
- default:
- cma_hdr = hdr;
- cma_hdr->cma_version = CMA_VERSION;
- cma_set_ip_ver(cma_hdr, 6);
- cma_hdr->src_addr.ip6 = src6->sin6_addr;
- cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
- cma_hdr->port = src6->sin6_port;
- break;
- }
+ src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
+ dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
+
+ cma_set_ip_ver(cma_hdr, 6);
+ cma_hdr->src_addr.ip6 = src6->sin6_addr;
+ cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
+ cma_hdr->port = src6->sin6_port;
}
return 0;
}
@@ -2499,15 +2638,10 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
event.status = ib_event->param.sidr_rep_rcvd.status;
break;
}
- ret = cma_set_qkey(id_priv);
+ ret = cma_set_qkey(id_priv, rep->qkey);
if (ret) {
event.event = RDMA_CM_EVENT_ADDR_ERROR;
- event.status = -EINVAL;
- break;
- }
- if (id_priv->qkey != rep->qkey) {
- event.event = RDMA_CM_EVENT_UNREACHABLE;
- event.status = -EINVAL;
+ event.status = ret;
break;
}
ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num,
@@ -2542,27 +2676,31 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
struct ib_cm_sidr_req_param req;
- struct rdma_route *route;
struct ib_cm_id *id;
- int ret;
+ int offset, ret;
- req.private_data_len = sizeof(struct cma_hdr) +
- conn_param->private_data_len;
+ offset = cma_user_data_offset(id_priv);
+ req.private_data_len = offset + conn_param->private_data_len;
if (req.private_data_len < conn_param->private_data_len)
return -EINVAL;
- req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
- if (!req.private_data)
- return -ENOMEM;
+ if (req.private_data_len) {
+ req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+ if (!req.private_data)
+ return -ENOMEM;
+ } else {
+ req.private_data = NULL;
+ }
if (conn_param->private_data && conn_param->private_data_len)
- memcpy((void *) req.private_data + sizeof(struct cma_hdr),
+ memcpy((void *) req.private_data + offset,
conn_param->private_data, conn_param->private_data_len);
- route = &id_priv->id.route;
- ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route);
- if (ret)
- goto out;
+ if (req.private_data) {
+ ret = cma_format_hdr((void *) req.private_data, id_priv);
+ if (ret)
+ goto out;
+ }
id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
id_priv);
@@ -2572,9 +2710,8 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
}
id_priv->cm_id.ib = id;
- req.path = route->path_rec;
- req.service_id = cma_get_service_id(id_priv->id.ps,
- (struct sockaddr *) &route->addr.dst_addr);
+ req.path = id_priv->id.route.path_rec;
+ req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
req.max_cm_retries = CMA_MAX_CM_RETRIES;
@@ -2598,14 +2735,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
int offset, ret;
memset(&req, 0, sizeof req);
- offset = cma_user_data_offset(id_priv->id.ps);
+ offset = cma_user_data_offset(id_priv);
req.private_data_len = offset + conn_param->private_data_len;
if (req.private_data_len < conn_param->private_data_len)
return -EINVAL;
- private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
- if (!private_data)
- return -ENOMEM;
+ if (req.private_data_len) {
+ private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+ if (!private_data)
+ return -ENOMEM;
+ } else {
+ private_data = NULL;
+ }
if (conn_param->private_data && conn_param->private_data_len)
memcpy(private_data + offset, conn_param->private_data,
@@ -2619,17 +2760,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
id_priv->cm_id.ib = id;
route = &id_priv->id.route;
- ret = cma_format_hdr(private_data, id_priv->id.ps, route);
- if (ret)
- goto out;
- req.private_data = private_data;
+ if (private_data) {
+ ret = cma_format_hdr(private_data, id_priv);
+ if (ret)
+ goto out;
+ req.private_data = private_data;
+ }
req.primary_path = &route->path_rec[0];
if (route->num_paths == 2)
req.alternate_path = &route->path_rec[1];
- req.service_id = cma_get_service_id(id_priv->id.ps,
- (struct sockaddr *) &route->addr.dst_addr);
+ req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
req.qp_num = id_priv->qp_num;
req.qp_type = id_priv->id.qp_type;
req.starting_psn = id_priv->seq_num;
@@ -2668,10 +2810,10 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
id_priv->cm_id.iw = cm_id;
- sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
+ sin = (struct sockaddr_in *) cma_src_addr(id_priv);
cm_id->local_addr = *sin;
- sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
+ sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
cm_id->remote_addr = *sin;
ret = cma_modify_qp_rtr(id_priv, conn_param);
@@ -2789,7 +2931,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
}
static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
- enum ib_cm_sidr_status status,
+ enum ib_cm_sidr_status status, u32 qkey,
const void *private_data, int private_data_len)
{
struct ib_cm_sidr_rep_param rep;
@@ -2798,7 +2940,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
memset(&rep, 0, sizeof rep);
rep.status = status;
if (status == IB_SIDR_SUCCESS) {
- ret = cma_set_qkey(id_priv);
+ ret = cma_set_qkey(id_priv, qkey);
if (ret)
return ret;
rep.qp_num = id_priv->qp_num;
@@ -2832,11 +2974,12 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
if (id->qp_type == IB_QPT_UD) {
if (conn_param)
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
+ conn_param->qkey,
conn_param->private_data,
conn_param->private_data_len);
else
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
- NULL, 0);
+ 0, NULL, 0);
} else {
if (conn_param)
ret = cma_accept_ib(id_priv, conn_param);
@@ -2897,7 +3040,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
if (id->qp_type == IB_QPT_UD)
- ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
+ ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0,
private_data, private_data_len);
else
ret = ib_send_cm_rej(id_priv->cm_id.ib,
@@ -2958,6 +3101,8 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
return 0;
+ if (!status)
+ status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
mutex_lock(&id_priv->qp_mutex);
if (!status && id_priv->id.qp)
status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
@@ -3004,6 +3149,8 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
0xFF10A01B)) {
/* IPv6 address is an SA assigned MGID. */
memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+ } else if (addr->sa_family == AF_IB) {
+ memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid);
} else if ((addr->sa_family == AF_INET6)) {
ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
if (id_priv->id.ps == RDMA_PS_UDP)
@@ -3031,9 +3178,12 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
if (ret)
return ret;
+ ret = cma_set_qkey(id_priv, 0);
+ if (ret)
+ return ret;
+
cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
- if (id_priv->id.ps == RDMA_PS_UDP)
- rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+ rec.qkey = cpu_to_be32(id_priv->qkey);
rdma_addr_get_sgid(dev_addr, &rec.port_gid);
rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
rec.join_state = 1;
@@ -3170,7 +3320,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
if (!mc)
return -ENOMEM;
- memcpy(&mc->addr, addr, ip_addr_size(addr));
+ memcpy(&mc->addr, addr, rdma_addr_size(addr));
mc->context = context;
mc->id_priv = id_priv;
@@ -3215,7 +3365,7 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
id_priv = container_of(id, struct rdma_id_private, id);
spin_lock_irq(&id_priv->lock);
list_for_each_entry(mc, &id_priv->mc_list, list) {
- if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) {
+ if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
list_del(&mc->list);
spin_unlock_irq(&id_priv->lock);
@@ -3436,33 +3586,16 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
id_stats->bound_dev_if =
id->route.addr.dev_addr.bound_dev_if;
- if (id->route.addr.src_addr.ss_family == AF_INET) {
- if (ibnl_put_attr(skb, nlh,
- sizeof(struct sockaddr_in),
- &id->route.addr.src_addr,
- RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
- goto out;
- }
- if (ibnl_put_attr(skb, nlh,
- sizeof(struct sockaddr_in),
- &id->route.addr.dst_addr,
- RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
- goto out;
- }
- } else if (id->route.addr.src_addr.ss_family == AF_INET6) {
- if (ibnl_put_attr(skb, nlh,
- sizeof(struct sockaddr_in6),
- &id->route.addr.src_addr,
- RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
- goto out;
- }
- if (ibnl_put_attr(skb, nlh,
- sizeof(struct sockaddr_in6),
- &id->route.addr.dst_addr,
- RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
- goto out;
- }
- }
+ if (ibnl_put_attr(skb, nlh,
+ rdma_addr_size(cma_src_addr(id_priv)),
+ cma_src_addr(id_priv),
+ RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
+ goto out;
+ if (ibnl_put_attr(skb, nlh,
+ rdma_addr_size(cma_src_addr(id_priv)),
+ cma_dst_addr(id_priv),
+ RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
+ goto out;
id_stats->pid = id_priv->owner;
id_stats->port_space = id->ps;
@@ -3527,7 +3660,6 @@ static void __exit cma_cleanup(void)
rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq);
- idr_destroy(&sdp_ps);
idr_destroy(&tcp_ps);
idr_destroy(&udp_ps);
idr_destroy(&ipoib_ps);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 934f45e79e5e..9838ca484389 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -652,6 +652,12 @@ void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec)
}
EXPORT_SYMBOL(ib_sa_unpack_path);
+void ib_sa_pack_path(struct ib_sa_path_rec *rec, void *attribute)
+{
+ ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, attribute);
+}
+EXPORT_SYMBOL(ib_sa_pack_path);
+
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
int status,
struct ib_sa_mad *mad)
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 99904f7d59e3..cde1e7b5b85d 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -545,8 +545,10 @@ static int add_port(struct ib_device *device, int port_num,
p->gid_group.name = "gids";
p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
- if (!p->gid_group.attrs)
+ if (!p->gid_group.attrs) {
+ ret = -ENOMEM;
goto err_remove_pma;
+ }
ret = sysfs_create_group(&p->kobj, &p->gid_group);
if (ret)
@@ -555,8 +557,10 @@ static int add_port(struct ib_device *device, int port_num,
p->pkey_group.name = "pkeys";
p->pkey_group.attrs = alloc_group_attrs(show_port_pkey,
attr.pkey_tbl_len);
- if (!p->pkey_group.attrs)
+ if (!p->pkey_group.attrs) {
+ ret = -ENOMEM;
goto err_remove_gid;
+ }
ret = sysfs_create_group(&p->kobj, &p->pkey_group);
if (ret)
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 5ca44cd9b00c..b0f189be543b 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -47,6 +47,8 @@
#include <rdma/ib_marshall.h>
#include <rdma/rdma_cm.h>
#include <rdma/rdma_cm_ib.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib.h>
MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -510,10 +512,10 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
return ret;
}
-static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
+static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,
int in_len, int out_len)
{
- struct rdma_ucm_bind_addr cmd;
+ struct rdma_ucm_bind_ip cmd;
struct ucma_context *ctx;
int ret;
@@ -529,24 +531,75 @@ static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
return ret;
}
+static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_bind cmd;
+ struct sockaddr *addr;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ addr = (struct sockaddr *) &cmd.addr;
+ if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+ return -EINVAL;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_bind_addr(ctx->cm_id, addr);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_resolve_ip(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_resolve_ip cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+ (struct sockaddr *) &cmd.dst_addr,
+ cmd.timeout_ms);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
static ssize_t ucma_resolve_addr(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
{
struct rdma_ucm_resolve_addr cmd;
+ struct sockaddr *src, *dst;
struct ucma_context *ctx;
int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
+ src = (struct sockaddr *) &cmd.src_addr;
+ dst = (struct sockaddr *) &cmd.dst_addr;
+ if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
+ !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+ return -EINVAL;
+
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
- (struct sockaddr *) &cmd.dst_addr,
- cmd.timeout_ms);
+ ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
ucma_put_ctx(ctx);
return ret;
}
@@ -649,7 +702,7 @@ static ssize_t ucma_query_route(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
{
- struct rdma_ucm_query_route cmd;
+ struct rdma_ucm_query cmd;
struct rdma_ucm_query_route_resp resp;
struct ucma_context *ctx;
struct sockaddr *addr;
@@ -709,7 +762,162 @@ out:
return ret;
}
-static void ucma_copy_conn_param(struct rdma_conn_param *dst,
+static void ucma_query_device_addr(struct rdma_cm_id *cm_id,
+ struct rdma_ucm_query_addr_resp *resp)
+{
+ if (!cm_id->device)
+ return;
+
+ resp->node_guid = (__force __u64) cm_id->device->node_guid;
+ resp->port_num = cm_id->port_num;
+ resp->pkey = (__force __u16) cpu_to_be16(
+ ib_addr_get_pkey(&cm_id->route.addr.dev_addr));
+}
+
+static ssize_t ucma_query_addr(struct ucma_context *ctx,
+ void __user *response, int out_len)
+{
+ struct rdma_ucm_query_addr_resp resp;
+ struct sockaddr *addr;
+ int ret = 0;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ memset(&resp, 0, sizeof resp);
+
+ addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
+ resp.src_size = rdma_addr_size(addr);
+ memcpy(&resp.src_addr, addr, resp.src_size);
+
+ addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr;
+ resp.dst_size = rdma_addr_size(addr);
+ memcpy(&resp.dst_addr, addr, resp.dst_size);
+
+ ucma_query_device_addr(ctx->cm_id, &resp);
+
+ if (copy_to_user(response, &resp, sizeof(resp)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static ssize_t ucma_query_path(struct ucma_context *ctx,
+ void __user *response, int out_len)
+{
+ struct rdma_ucm_query_path_resp *resp;
+ int i, ret = 0;
+
+ if (out_len < sizeof(*resp))
+ return -ENOSPC;
+
+ resp = kzalloc(out_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ resp->num_paths = ctx->cm_id->route.num_paths;
+ for (i = 0, out_len -= sizeof(*resp);
+ i < resp->num_paths && out_len > sizeof(struct ib_path_rec_data);
+ i++, out_len -= sizeof(struct ib_path_rec_data)) {
+
+ resp->path_data[i].flags = IB_PATH_GMP | IB_PATH_PRIMARY |
+ IB_PATH_BIDIRECTIONAL;
+ ib_sa_pack_path(&ctx->cm_id->route.path_rec[i],
+ &resp->path_data[i].path_rec);
+ }
+
+ if (copy_to_user(response, resp,
+ sizeof(*resp) + (i * sizeof(struct ib_path_rec_data))))
+ ret = -EFAULT;
+
+ kfree(resp);
+ return ret;
+}
+
+static ssize_t ucma_query_gid(struct ucma_context *ctx,
+ void __user *response, int out_len)
+{
+ struct rdma_ucm_query_addr_resp resp;
+ struct sockaddr_ib *addr;
+ int ret = 0;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ memset(&resp, 0, sizeof resp);
+
+ ucma_query_device_addr(ctx->cm_id, &resp);
+
+ addr = (struct sockaddr_ib *) &resp.src_addr;
+ resp.src_size = sizeof(*addr);
+ if (ctx->cm_id->route.addr.src_addr.ss_family == AF_IB) {
+ memcpy(addr, &ctx->cm_id->route.addr.src_addr, resp.src_size);
+ } else {
+ addr->sib_family = AF_IB;
+ addr->sib_pkey = (__force __be16) resp.pkey;
+ rdma_addr_get_sgid(&ctx->cm_id->route.addr.dev_addr,
+ (union ib_gid *) &addr->sib_addr);
+ addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+ &ctx->cm_id->route.addr.src_addr);
+ }
+
+ addr = (struct sockaddr_ib *) &resp.dst_addr;
+ resp.dst_size = sizeof(*addr);
+ if (ctx->cm_id->route.addr.dst_addr.ss_family == AF_IB) {
+ memcpy(addr, &ctx->cm_id->route.addr.dst_addr, resp.dst_size);
+ } else {
+ addr->sib_family = AF_IB;
+ addr->sib_pkey = (__force __be16) resp.pkey;
+ rdma_addr_get_dgid(&ctx->cm_id->route.addr.dev_addr,
+ (union ib_gid *) &addr->sib_addr);
+ addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+ &ctx->cm_id->route.addr.dst_addr);
+ }
+
+ if (copy_to_user(response, &resp, sizeof(resp)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static ssize_t ucma_query(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_query cmd;
+ struct ucma_context *ctx;
+ void __user *response;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ response = (void __user *)(unsigned long) cmd.response;
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ switch (cmd.option) {
+ case RDMA_USER_CM_QUERY_ADDR:
+ ret = ucma_query_addr(ctx, response, out_len);
+ break;
+ case RDMA_USER_CM_QUERY_PATH:
+ ret = ucma_query_path(ctx, response, out_len);
+ break;
+ case RDMA_USER_CM_QUERY_GID:
+ ret = ucma_query_gid(ctx, response, out_len);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static void ucma_copy_conn_param(struct rdma_cm_id *id,
+ struct rdma_conn_param *dst,
struct rdma_ucm_conn_param *src)
{
dst->private_data = src->private_data;
@@ -721,6 +929,7 @@ static void ucma_copy_conn_param(struct rdma_conn_param *dst,
dst->rnr_retry_count = src->rnr_retry_count;
dst->srq = src->srq;
dst->qp_num = src->qp_num;
+ dst->qkey = (id->route.addr.src_addr.ss_family == AF_IB) ? src->qkey : 0;
}
static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
@@ -741,7 +950,7 @@ static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+ ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
ret = rdma_connect(ctx->cm_id, &conn_param);
ucma_put_ctx(ctx);
return ret;
@@ -784,7 +993,7 @@ static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,
return PTR_ERR(ctx);
if (cmd.conn_param.valid) {
- ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+ ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
mutex_lock(&file->mut);
ret = rdma_accept(ctx->cm_id, &conn_param);
if (!ret)
@@ -1020,23 +1229,23 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
return ret;
}
-static ssize_t ucma_join_multicast(struct ucma_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
+static ssize_t ucma_process_join(struct ucma_file *file,
+ struct rdma_ucm_join_mcast *cmd, int out_len)
{
- struct rdma_ucm_join_mcast cmd;
struct rdma_ucm_create_id_resp resp;
struct ucma_context *ctx;
struct ucma_multicast *mc;
+ struct sockaddr *addr;
int ret;
if (out_len < sizeof(resp))
return -ENOSPC;
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
+ addr = (struct sockaddr *) &cmd->addr;
+ if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+ return -EINVAL;
- ctx = ucma_get_ctx(file, cmd.id);
+ ctx = ucma_get_ctx(file, cmd->id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
@@ -1047,14 +1256,14 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
goto err1;
}
- mc->uid = cmd.uid;
- memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);
+ mc->uid = cmd->uid;
+ memcpy(&mc->addr, addr, cmd->addr_size);
ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);
if (ret)
goto err2;
resp.id = mc->id;
- if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ if (copy_to_user((void __user *)(unsigned long) cmd->response,
&resp, sizeof(resp))) {
ret = -EFAULT;
goto err3;
@@ -1079,6 +1288,38 @@ err1:
return ret;
}
+static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_join_ip_mcast cmd;
+ struct rdma_ucm_join_mcast join_cmd;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ join_cmd.response = cmd.response;
+ join_cmd.uid = cmd.uid;
+ join_cmd.id = cmd.id;
+ join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+ join_cmd.reserved = 0;
+ memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
+
+ return ucma_process_join(file, &join_cmd, out_len);
+}
+
+static ssize_t ucma_join_multicast(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_join_mcast cmd;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ return ucma_process_join(file, &cmd, out_len);
+}
+
static ssize_t ucma_leave_multicast(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
@@ -1221,25 +1462,29 @@ file_put:
static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len) = {
- [RDMA_USER_CM_CMD_CREATE_ID] = ucma_create_id,
- [RDMA_USER_CM_CMD_DESTROY_ID] = ucma_destroy_id,
- [RDMA_USER_CM_CMD_BIND_ADDR] = ucma_bind_addr,
- [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
- [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route,
- [RDMA_USER_CM_CMD_QUERY_ROUTE] = ucma_query_route,
- [RDMA_USER_CM_CMD_CONNECT] = ucma_connect,
- [RDMA_USER_CM_CMD_LISTEN] = ucma_listen,
- [RDMA_USER_CM_CMD_ACCEPT] = ucma_accept,
- [RDMA_USER_CM_CMD_REJECT] = ucma_reject,
- [RDMA_USER_CM_CMD_DISCONNECT] = ucma_disconnect,
- [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
- [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event,
- [RDMA_USER_CM_CMD_GET_OPTION] = NULL,
- [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option,
- [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
- [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
- [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
- [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id
+ [RDMA_USER_CM_CMD_CREATE_ID] = ucma_create_id,
+ [RDMA_USER_CM_CMD_DESTROY_ID] = ucma_destroy_id,
+ [RDMA_USER_CM_CMD_BIND_IP] = ucma_bind_ip,
+ [RDMA_USER_CM_CMD_RESOLVE_IP] = ucma_resolve_ip,
+ [RDMA_USER_CM_CMD_RESOLVE_ROUTE] = ucma_resolve_route,
+ [RDMA_USER_CM_CMD_QUERY_ROUTE] = ucma_query_route,
+ [RDMA_USER_CM_CMD_CONNECT] = ucma_connect,
+ [RDMA_USER_CM_CMD_LISTEN] = ucma_listen,
+ [RDMA_USER_CM_CMD_ACCEPT] = ucma_accept,
+ [RDMA_USER_CM_CMD_REJECT] = ucma_reject,
+ [RDMA_USER_CM_CMD_DISCONNECT] = ucma_disconnect,
+ [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
+ [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event,
+ [RDMA_USER_CM_CMD_GET_OPTION] = NULL,
+ [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option,
+ [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
+ [RDMA_USER_CM_CMD_JOIN_IP_MCAST] = ucma_join_ip_multicast,
+ [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
+ [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id,
+ [RDMA_USER_CM_CMD_QUERY] = ucma_query,
+ [RDMA_USER_CM_CMD_BIND] = ucma_bind,
+ [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
+ [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast
};
static ssize_t ucma_write(struct file *filp, const char __user *buf,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index a7d00f6b3bc1..b3c07b0c9f26 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -334,7 +334,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
resp.num_comp_vectors = file->device->num_comp_vectors;
- ret = get_unused_fd();
+ ret = get_unused_fd_flags(O_CLOEXEC);
if (ret < 0)
goto err_free;
resp.async_fd = ret;
@@ -1184,7 +1184,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- ret = get_unused_fd();
+ ret = get_unused_fd_flags(O_CLOEXEC);
if (ret < 0)
return ret;
resp.fd = ret;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index e5649e8b215d..b57c0befd962 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -883,7 +883,8 @@ u16 iwch_rqes_posted(struct iwch_qp *qhp)
{
union t3_wr *wqe = qhp->wq.queue;
u16 count = 0;
- while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
+
+ while (count < USHRT_MAX && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
count++;
wqe++;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 982e3efd98d3..cd8d290a09fc 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -211,6 +211,7 @@ static int ehca_create_slab_caches(void)
if (!ctblk_cache) {
ehca_gen_err("Cannot create ctblk SLAB cache.");
ehca_cleanup_small_qp_cache();
+ ret = -ENOMEM;
goto create_slab_caches6;
}
#endif
diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig
new file mode 100644
index 000000000000..8e6aebfaf8a4
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/Kconfig
@@ -0,0 +1,10 @@
+config MLX5_INFINIBAND
+ tristate "Mellanox Connect-IB HCA support"
+ depends on NETDEVICES && ETHERNET && PCI && X86
+ select NET_VENDOR_MELLANOX
+ select MLX5_CORE
+ ---help---
+ This driver provides low-level InfiniBand support for
+ Mellanox Connect-IB PCI Express host channel adapters (HCAs).
+ This is required to use InfiniBand protocols such as
+ IP-over-IB or SRP with these devices.
diff --git a/drivers/infiniband/hw/mlx5/Makefile b/drivers/infiniband/hw/mlx5/Makefile
new file mode 100644
index 000000000000..4ea0135af484
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MLX5_INFINIBAND) += mlx5_ib.o
+
+mlx5_ib-y := main.o cq.o doorbell.o qp.o mem.o srq.o mr.o ah.o mad.o
diff --git a/drivers/infiniband/hw/mlx5/ah.c b/drivers/infiniband/hw/mlx5/ah.c
new file mode 100644
index 000000000000..39ab0caefdf9
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/ah.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx5_ib.h"
+
+struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr,
+ struct mlx5_ib_ah *ah)
+{
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ memcpy(ah->av.rgid, &ah_attr->grh.dgid, 16);
+ ah->av.grh_gid_fl = cpu_to_be32(ah_attr->grh.flow_label |
+ (1 << 30) |
+ ah_attr->grh.sgid_index << 20);
+ ah->av.hop_limit = ah_attr->grh.hop_limit;
+ ah->av.tclass = ah_attr->grh.traffic_class;
+ }
+
+ ah->av.rlid = cpu_to_be16(ah_attr->dlid);
+ ah->av.fl_mlid = ah_attr->src_path_bits & 0x7f;
+ ah->av.stat_rate_sl = (ah_attr->static_rate << 4) | (ah_attr->sl & 0xf);
+
+ return &ah->ibah;
+}
+
+struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ struct mlx5_ib_ah *ah;
+
+ ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
+ if (!ah)
+ return ERR_PTR(-ENOMEM);
+
+ return create_ib_ah(ah_attr, ah); /* never fails */
+}
+
+int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+ struct mlx5_ib_ah *ah = to_mah(ibah);
+ u32 tmp;
+
+ memset(ah_attr, 0, sizeof(*ah_attr));
+
+ tmp = be32_to_cpu(ah->av.grh_gid_fl);
+ if (tmp & (1 << 30)) {
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.sgid_index = (tmp >> 20) & 0xff;
+ ah_attr->grh.flow_label = tmp & 0xfffff;
+ memcpy(&ah_attr->grh.dgid, ah->av.rgid, 16);
+ ah_attr->grh.hop_limit = ah->av.hop_limit;
+ ah_attr->grh.traffic_class = ah->av.tclass;
+ }
+ ah_attr->dlid = be16_to_cpu(ah->av.rlid);
+ ah_attr->static_rate = ah->av.stat_rate_sl >> 4;
+ ah_attr->sl = ah->av.stat_rate_sl & 0xf;
+
+ return 0;
+}
+
+int mlx5_ib_destroy_ah(struct ib_ah *ah)
+{
+ kfree(to_mah(ah));
+ return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
new file mode 100644
index 000000000000..344ab03948a3
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kref.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+#include "user.h"
+
+static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq)
+{
+ struct ib_cq *ibcq = &to_mibcq(cq)->ibcq;
+
+ ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+static void mlx5_ib_cq_event(struct mlx5_core_cq *mcq, enum mlx5_event type)
+{
+ struct mlx5_ib_cq *cq = container_of(mcq, struct mlx5_ib_cq, mcq);
+ struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
+ struct ib_cq *ibcq = &cq->ibcq;
+ struct ib_event event;
+
+ if (type != MLX5_EVENT_TYPE_CQ_ERROR) {
+ mlx5_ib_warn(dev, "Unexpected event type %d on CQ %06x\n",
+ type, mcq->cqn);
+ return;
+ }
+
+ if (ibcq->event_handler) {
+ event.device = &dev->ib_dev;
+ event.event = IB_EVENT_CQ_ERR;
+ event.element.cq = ibcq;
+ ibcq->event_handler(&event, ibcq->cq_context);
+ }
+}
+
+static void *get_cqe_from_buf(struct mlx5_ib_cq_buf *buf, int n, int size)
+{
+ return mlx5_buf_offset(&buf->buf, n * size);
+}
+
+static void *get_cqe(struct mlx5_ib_cq *cq, int n)
+{
+ return get_cqe_from_buf(&cq->buf, n, cq->mcq.cqe_sz);
+}
+
+static void *get_sw_cqe(struct mlx5_ib_cq *cq, int n)
+{
+ void *cqe = get_cqe(cq, n & cq->ibcq.cqe);
+ struct mlx5_cqe64 *cqe64;
+
+ cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+ return ((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^
+ !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe;
+}
+
+static void *next_cqe_sw(struct mlx5_ib_cq *cq)
+{
+ return get_sw_cqe(cq, cq->mcq.cons_index);
+}
+
+static enum ib_wc_opcode get_umr_comp(struct mlx5_ib_wq *wq, int idx)
+{
+ switch (wq->wr_data[idx]) {
+ case MLX5_IB_WR_UMR:
+ return 0;
+
+ case IB_WR_LOCAL_INV:
+ return IB_WC_LOCAL_INV;
+
+ case IB_WR_FAST_REG_MR:
+ return IB_WC_FAST_REG_MR;
+
+ default:
+ pr_warn("unknown completion status\n");
+ return 0;
+ }
+}
+
+static void handle_good_req(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
+ struct mlx5_ib_wq *wq, int idx)
+{
+ wc->wc_flags = 0;
+ switch (be32_to_cpu(cqe->sop_drop_qpn) >> 24) {
+ case MLX5_OPCODE_RDMA_WRITE_IMM:
+ wc->wc_flags |= IB_WC_WITH_IMM;
+ case MLX5_OPCODE_RDMA_WRITE:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case MLX5_OPCODE_SEND_IMM:
+ wc->wc_flags |= IB_WC_WITH_IMM;
+ case MLX5_OPCODE_SEND:
+ case MLX5_OPCODE_SEND_INVAL:
+ wc->opcode = IB_WC_SEND;
+ break;
+ case MLX5_OPCODE_RDMA_READ:
+ wc->opcode = IB_WC_RDMA_READ;
+ wc->byte_len = be32_to_cpu(cqe->byte_cnt);
+ break;
+ case MLX5_OPCODE_ATOMIC_CS:
+ wc->opcode = IB_WC_COMP_SWAP;
+ wc->byte_len = 8;
+ break;
+ case MLX5_OPCODE_ATOMIC_FA:
+ wc->opcode = IB_WC_FETCH_ADD;
+ wc->byte_len = 8;
+ break;
+ case MLX5_OPCODE_ATOMIC_MASKED_CS:
+ wc->opcode = IB_WC_MASKED_COMP_SWAP;
+ wc->byte_len = 8;
+ break;
+ case MLX5_OPCODE_ATOMIC_MASKED_FA:
+ wc->opcode = IB_WC_MASKED_FETCH_ADD;
+ wc->byte_len = 8;
+ break;
+ case MLX5_OPCODE_BIND_MW:
+ wc->opcode = IB_WC_BIND_MW;
+ break;
+ case MLX5_OPCODE_UMR:
+ wc->opcode = get_umr_comp(wq, idx);
+ break;
+ }
+}
+
+enum {
+ MLX5_GRH_IN_BUFFER = 1,
+ MLX5_GRH_IN_CQE = 2,
+};
+
+static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
+ struct mlx5_ib_qp *qp)
+{
+ struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
+ struct mlx5_ib_srq *srq;
+ struct mlx5_ib_wq *wq;
+ u16 wqe_ctr;
+ u8 g;
+
+ if (qp->ibqp.srq || qp->ibqp.xrcd) {
+ struct mlx5_core_srq *msrq = NULL;
+
+ if (qp->ibqp.xrcd) {
+ msrq = mlx5_core_get_srq(&dev->mdev,
+ be32_to_cpu(cqe->srqn));
+ srq = to_mibsrq(msrq);
+ } else {
+ srq = to_msrq(qp->ibqp.srq);
+ }
+ if (srq) {
+ wqe_ctr = be16_to_cpu(cqe->wqe_counter);
+ wc->wr_id = srq->wrid[wqe_ctr];
+ mlx5_ib_free_srq_wqe(srq, wqe_ctr);
+ if (msrq && atomic_dec_and_test(&msrq->refcount))
+ complete(&msrq->free);
+ }
+ } else {
+ wq = &qp->rq;
+ wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+ ++wq->tail;
+ }
+ wc->byte_len = be32_to_cpu(cqe->byte_cnt);
+
+ switch (cqe->op_own >> 4) {
+ case MLX5_CQE_RESP_WR_IMM:
+ wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ wc->ex.imm_data = cqe->imm_inval_pkey;
+ break;
+ case MLX5_CQE_RESP_SEND:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = 0;
+ break;
+ case MLX5_CQE_RESP_SEND_IMM:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ wc->ex.imm_data = cqe->imm_inval_pkey;
+ break;
+ case MLX5_CQE_RESP_SEND_INV:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = IB_WC_WITH_INVALIDATE;
+ wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey);
+ break;
+ }
+ wc->slid = be16_to_cpu(cqe->slid);
+ wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf;
+ wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff;
+ wc->dlid_path_bits = cqe->ml_path;
+ g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
+ wc->wc_flags |= g ? IB_WC_GRH : 0;
+ wc->pkey_index = be32_to_cpu(cqe->imm_inval_pkey) & 0xffff;
+}
+
+static void dump_cqe(struct mlx5_ib_dev *dev, struct mlx5_err_cqe *cqe)
+{
+ __be32 *p = (__be32 *)cqe;
+ int i;
+
+ mlx5_ib_warn(dev, "dump error cqe\n");
+ for (i = 0; i < sizeof(*cqe) / 16; i++, p += 4)
+ pr_info("%08x %08x %08x %08x\n", be32_to_cpu(p[0]),
+ be32_to_cpu(p[1]), be32_to_cpu(p[2]),
+ be32_to_cpu(p[3]));
+}
+
+static void mlx5_handle_error_cqe(struct mlx5_ib_dev *dev,
+ struct mlx5_err_cqe *cqe,
+ struct ib_wc *wc)
+{
+ int dump = 1;
+
+ switch (cqe->syndrome) {
+ case MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR:
+ wc->status = IB_WC_LOC_LEN_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR:
+ wc->status = IB_WC_LOC_QP_OP_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_LOCAL_PROT_ERR:
+ wc->status = IB_WC_LOC_PROT_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_WR_FLUSH_ERR:
+ dump = 0;
+ wc->status = IB_WC_WR_FLUSH_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_MW_BIND_ERR:
+ wc->status = IB_WC_MW_BIND_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_BAD_RESP_ERR:
+ wc->status = IB_WC_BAD_RESP_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR:
+ wc->status = IB_WC_LOC_ACCESS_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR:
+ wc->status = IB_WC_REM_INV_REQ_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR:
+ wc->status = IB_WC_REM_ACCESS_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_REMOTE_OP_ERR:
+ wc->status = IB_WC_REM_OP_ERR;
+ break;
+ case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
+ wc->status = IB_WC_RETRY_EXC_ERR;
+ dump = 0;
+ break;
+ case MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR:
+ wc->status = IB_WC_RNR_RETRY_EXC_ERR;
+ dump = 0;
+ break;
+ case MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR:
+ wc->status = IB_WC_REM_ABORT_ERR;
+ break;
+ default:
+ wc->status = IB_WC_GENERAL_ERR;
+ break;
+ }
+
+ wc->vendor_err = cqe->vendor_err_synd;
+ if (dump)
+ dump_cqe(dev, cqe);
+}
+
+static int is_atomic_response(struct mlx5_ib_qp *qp, uint16_t idx)
+{
+ /* TBD: waiting decision
+ */
+ return 0;
+}
+
+static void *mlx5_get_atomic_laddr(struct mlx5_ib_qp *qp, uint16_t idx)
+{
+ struct mlx5_wqe_data_seg *dpseg;
+ void *addr;
+
+ dpseg = mlx5_get_send_wqe(qp, idx) + sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_atomic_seg);
+ addr = (void *)(unsigned long)be64_to_cpu(dpseg->addr);
+ return addr;
+}
+
+static void handle_atomic(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+ uint16_t idx)
+{
+ void *addr;
+ int byte_count;
+ int i;
+
+ if (!is_atomic_response(qp, idx))
+ return;
+
+ byte_count = be32_to_cpu(cqe64->byte_cnt);
+ addr = mlx5_get_atomic_laddr(qp, idx);
+
+ if (byte_count == 4) {
+ *(uint32_t *)addr = be32_to_cpu(*((__be32 *)addr));
+ } else {
+ for (i = 0; i < byte_count; i += 8) {
+ *(uint64_t *)addr = be64_to_cpu(*((__be64 *)addr));
+ addr += 8;
+ }
+ }
+
+ return;
+}
+
+static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+ u16 tail, u16 head)
+{
+ int idx;
+
+ do {
+ idx = tail & (qp->sq.wqe_cnt - 1);
+ handle_atomic(qp, cqe64, idx);
+ if (idx == head)
+ break;
+
+ tail = qp->sq.w_list[idx].next;
+ } while (1);
+ tail = qp->sq.w_list[idx].next;
+ qp->sq.last_poll = tail;
+}
+
+static int mlx5_poll_one(struct mlx5_ib_cq *cq,
+ struct mlx5_ib_qp **cur_qp,
+ struct ib_wc *wc)
+{
+ struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
+ struct mlx5_err_cqe *err_cqe;
+ struct mlx5_cqe64 *cqe64;
+ struct mlx5_core_qp *mqp;
+ struct mlx5_ib_wq *wq;
+ uint8_t opcode;
+ uint32_t qpn;
+ u16 wqe_ctr;
+ void *cqe;
+ int idx;
+
+ cqe = next_cqe_sw(cq);
+ if (!cqe)
+ return -EAGAIN;
+
+ cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+
+ ++cq->mcq.cons_index;
+
+ /* Make sure we read CQ entry contents after we've checked the
+ * ownership bit.
+ */
+ rmb();
+
+ /* TBD: resize CQ */
+
+ qpn = ntohl(cqe64->sop_drop_qpn) & 0xffffff;
+ if (!*cur_qp || (qpn != (*cur_qp)->ibqp.qp_num)) {
+ /* We do not have to take the QP table lock here,
+ * because CQs will be locked while QPs are removed
+ * from the table.
+ */
+ mqp = __mlx5_qp_lookup(&dev->mdev, qpn);
+ if (unlikely(!mqp)) {
+ mlx5_ib_warn(dev, "CQE@CQ %06x for unknown QPN %6x\n",
+ cq->mcq.cqn, qpn);
+ return -EINVAL;
+ }
+
+ *cur_qp = to_mibqp(mqp);
+ }
+
+ wc->qp = &(*cur_qp)->ibqp;
+ opcode = cqe64->op_own >> 4;
+ switch (opcode) {
+ case MLX5_CQE_REQ:
+ wq = &(*cur_qp)->sq;
+ wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+ idx = wqe_ctr & (wq->wqe_cnt - 1);
+ handle_good_req(wc, cqe64, wq, idx);
+ handle_atomics(*cur_qp, cqe64, wq->last_poll, idx);
+ wc->wr_id = wq->wrid[idx];
+ wq->tail = wq->wqe_head[idx] + 1;
+ wc->status = IB_WC_SUCCESS;
+ break;
+ case MLX5_CQE_RESP_WR_IMM:
+ case MLX5_CQE_RESP_SEND:
+ case MLX5_CQE_RESP_SEND_IMM:
+ case MLX5_CQE_RESP_SEND_INV:
+ handle_responder(wc, cqe64, *cur_qp);
+ wc->status = IB_WC_SUCCESS;
+ break;
+ case MLX5_CQE_RESIZE_CQ:
+ break;
+ case MLX5_CQE_REQ_ERR:
+ case MLX5_CQE_RESP_ERR:
+ err_cqe = (struct mlx5_err_cqe *)cqe64;
+ mlx5_handle_error_cqe(dev, err_cqe, wc);
+ mlx5_ib_dbg(dev, "%s error cqe on cqn 0x%x:\n",
+ opcode == MLX5_CQE_REQ_ERR ?
+ "Requestor" : "Responder", cq->mcq.cqn);
+ mlx5_ib_dbg(dev, "syndrome 0x%x, vendor syndrome 0x%x\n",
+ err_cqe->syndrome, err_cqe->vendor_err_synd);
+ if (opcode == MLX5_CQE_REQ_ERR) {
+ wq = &(*cur_qp)->sq;
+ wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+ idx = wqe_ctr & (wq->wqe_cnt - 1);
+ wc->wr_id = wq->wrid[idx];
+ wq->tail = wq->wqe_head[idx] + 1;
+ } else {
+ struct mlx5_ib_srq *srq;
+
+ if ((*cur_qp)->ibqp.srq) {
+ srq = to_msrq((*cur_qp)->ibqp.srq);
+ wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+ wc->wr_id = srq->wrid[wqe_ctr];
+ mlx5_ib_free_srq_wqe(srq, wqe_ctr);
+ } else {
+ wq = &(*cur_qp)->rq;
+ wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+ ++wq->tail;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ struct mlx5_ib_cq *cq = to_mcq(ibcq);
+ struct mlx5_ib_qp *cur_qp = NULL;
+ unsigned long flags;
+ int npolled;
+ int err = 0;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+ for (npolled = 0; npolled < num_entries; npolled++) {
+ err = mlx5_poll_one(cq, &cur_qp, wc + npolled);
+ if (err)
+ break;
+ }
+
+ if (npolled)
+ mlx5_cq_set_ci(&cq->mcq);
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ if (err == 0 || err == -EAGAIN)
+ return npolled;
+ else
+ return err;
+}
+
+int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+ mlx5_cq_arm(&to_mcq(ibcq)->mcq,
+ (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+ MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT,
+ to_mdev(ibcq->device)->mdev.priv.uuari.uars[0].map,
+ MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev.priv.cq_uar_lock));
+
+ return 0;
+}
+
+static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf,
+ int nent, int cqe_size)
+{
+ int err;
+
+ err = mlx5_buf_alloc(&dev->mdev, nent * cqe_size,
+ PAGE_SIZE * 2, &buf->buf);
+ if (err)
+ return err;
+
+ buf->cqe_size = cqe_size;
+
+ return 0;
+}
+
+static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
+{
+ mlx5_buf_free(&dev->mdev, &buf->buf);
+}
+
+static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
+ struct ib_ucontext *context, struct mlx5_ib_cq *cq,
+ int entries, struct mlx5_create_cq_mbox_in **cqb,
+ int *cqe_size, int *index, int *inlen)
+{
+ struct mlx5_ib_create_cq ucmd;
+ int page_shift;
+ int npages;
+ int ncont;
+ int err;
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
+ return -EFAULT;
+
+ if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128)
+ return -EINVAL;
+
+ *cqe_size = ucmd.cqe_size;
+
+ cq->buf.umem = ib_umem_get(context, ucmd.buf_addr,
+ entries * ucmd.cqe_size,
+ IB_ACCESS_LOCAL_WRITE, 1);
+ if (IS_ERR(cq->buf.umem)) {
+ err = PTR_ERR(cq->buf.umem);
+ return err;
+ }
+
+ err = mlx5_ib_db_map_user(to_mucontext(context), ucmd.db_addr,
+ &cq->db);
+ if (err)
+ goto err_umem;
+
+ mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, &npages, &page_shift,
+ &ncont, NULL);
+ mlx5_ib_dbg(dev, "addr 0x%llx, size %u, npages %d, page_shift %d, ncont %d\n",
+ ucmd.buf_addr, entries * ucmd.cqe_size, npages, page_shift, ncont);
+
+ *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * ncont;
+ *cqb = mlx5_vzalloc(*inlen);
+ if (!*cqb) {
+ err = -ENOMEM;
+ goto err_db;
+ }
+ mlx5_ib_populate_pas(dev, cq->buf.umem, page_shift, (*cqb)->pas, 0);
+ (*cqb)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+
+ *index = to_mucontext(context)->uuari.uars[0].index;
+
+ return 0;
+
+err_db:
+ mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db);
+
+err_umem:
+ ib_umem_release(cq->buf.umem);
+ return err;
+}
+
+static void destroy_cq_user(struct mlx5_ib_cq *cq, struct ib_ucontext *context)
+{
+ mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db);
+ ib_umem_release(cq->buf.umem);
+}
+
+static void init_cq_buf(struct mlx5_ib_cq *cq, int nent)
+{
+ int i;
+ void *cqe;
+ struct mlx5_cqe64 *cqe64;
+
+ for (i = 0; i < nent; i++) {
+ cqe = get_cqe(cq, i);
+ cqe64 = (cq->buf.cqe_size == 64) ? cqe : cqe + 64;
+ cqe64->op_own = 0xf1;
+ }
+}
+
+static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
+ int entries, int cqe_size,
+ struct mlx5_create_cq_mbox_in **cqb,
+ int *index, int *inlen)
+{
+ int err;
+
+ err = mlx5_db_alloc(&dev->mdev, &cq->db);
+ if (err)
+ return err;
+
+ cq->mcq.set_ci_db = cq->db.db;
+ cq->mcq.arm_db = cq->db.db + 1;
+ *cq->mcq.set_ci_db = 0;
+ *cq->mcq.arm_db = 0;
+ cq->mcq.cqe_sz = cqe_size;
+
+ err = alloc_cq_buf(dev, &cq->buf, entries, cqe_size);
+ if (err)
+ goto err_db;
+
+ init_cq_buf(cq, entries);
+
+ *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * cq->buf.buf.npages;
+ *cqb = mlx5_vzalloc(*inlen);
+ if (!*cqb) {
+ err = -ENOMEM;
+ goto err_buf;
+ }
+ mlx5_fill_page_array(&cq->buf.buf, (*cqb)->pas);
+
+ (*cqb)->ctx.log_pg_sz = cq->buf.buf.page_shift - PAGE_SHIFT;
+ *index = dev->mdev.priv.uuari.uars[0].index;
+
+ return 0;
+
+err_buf:
+ free_cq_buf(dev, &cq->buf);
+
+err_db:
+ mlx5_db_free(&dev->mdev, &cq->db);
+ return err;
+}
+
+static void destroy_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq)
+{
+ free_cq_buf(dev, &cq->buf);
+ mlx5_db_free(&dev->mdev, &cq->db);
+}
+
+struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries,
+ int vector, struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct mlx5_create_cq_mbox_in *cqb = NULL;
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_ib_cq *cq;
+ int uninitialized_var(index);
+ int uninitialized_var(inlen);
+ int cqe_size;
+ int irqn;
+ int eqn;
+ int err;
+
+ entries = roundup_pow_of_two(entries + 1);
+ if (entries < 1 || entries > dev->mdev.caps.max_cqes)
+ return ERR_PTR(-EINVAL);
+
+ cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+ if (!cq)
+ return ERR_PTR(-ENOMEM);
+
+ cq->ibcq.cqe = entries - 1;
+ mutex_init(&cq->resize_mutex);
+ spin_lock_init(&cq->lock);
+ cq->resize_buf = NULL;
+ cq->resize_umem = NULL;
+
+ if (context) {
+ err = create_cq_user(dev, udata, context, cq, entries,
+ &cqb, &cqe_size, &index, &inlen);
+ if (err)
+ goto err_create;
+ } else {
+ /* for now choose 64 bytes till we have a proper interface */
+ cqe_size = 64;
+ err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb,
+ &index, &inlen);
+ if (err)
+ goto err_create;
+ }
+
+ cq->cqe_size = cqe_size;
+ cqb->ctx.cqe_sz_flags = cqe_sz_to_mlx_sz(cqe_size) << 5;
+ cqb->ctx.log_sz_usr_page = cpu_to_be32((ilog2(entries) << 24) | index);
+ err = mlx5_vector2eqn(dev, vector, &eqn, &irqn);
+ if (err)
+ goto err_cqb;
+
+ cqb->ctx.c_eqn = cpu_to_be16(eqn);
+ cqb->ctx.db_record_addr = cpu_to_be64(cq->db.dma);
+
+ err = mlx5_core_create_cq(&dev->mdev, &cq->mcq, cqb, inlen);
+ if (err)
+ goto err_cqb;
+
+ mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn);
+ cq->mcq.irqn = irqn;
+ cq->mcq.comp = mlx5_ib_cq_comp;
+ cq->mcq.event = mlx5_ib_cq_event;
+
+ if (context)
+ if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof(__u32))) {
+ err = -EFAULT;
+ goto err_cmd;
+ }
+
+
+ mlx5_vfree(cqb);
+ return &cq->ibcq;
+
+err_cmd:
+ mlx5_core_destroy_cq(&dev->mdev, &cq->mcq);
+
+err_cqb:
+ mlx5_vfree(cqb);
+ if (context)
+ destroy_cq_user(cq, context);
+ else
+ destroy_cq_kernel(dev, cq);
+
+err_create:
+ kfree(cq);
+
+ return ERR_PTR(err);
+}
+
+
+int mlx5_ib_destroy_cq(struct ib_cq *cq)
+{
+ struct mlx5_ib_dev *dev = to_mdev(cq->device);
+ struct mlx5_ib_cq *mcq = to_mcq(cq);
+ struct ib_ucontext *context = NULL;
+
+ if (cq->uobject)
+ context = cq->uobject->context;
+
+ mlx5_core_destroy_cq(&dev->mdev, &mcq->mcq);
+ if (context)
+ destroy_cq_user(mcq, context);
+ else
+ destroy_cq_kernel(dev, mcq);
+
+ kfree(mcq);
+
+ return 0;
+}
+
+static int is_equal_rsn(struct mlx5_cqe64 *cqe64, struct mlx5_ib_srq *srq,
+ u32 rsn)
+{
+ u32 lrsn;
+
+ if (srq)
+ lrsn = be32_to_cpu(cqe64->srqn) & 0xffffff;
+ else
+ lrsn = be32_to_cpu(cqe64->sop_drop_qpn) & 0xffffff;
+
+ return rsn == lrsn;
+}
+
+void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 rsn, struct mlx5_ib_srq *srq)
+{
+ struct mlx5_cqe64 *cqe64, *dest64;
+ void *cqe, *dest;
+ u32 prod_index;
+ int nfreed = 0;
+ u8 owner_bit;
+
+ if (!cq)
+ return;
+
+ /* First we need to find the current producer index, so we
+ * know where to start cleaning from. It doesn't matter if HW
+ * adds new entries after this loop -- the QP we're worried
+ * about is already in RESET, so the new entries won't come
+ * from our QP and therefore don't need to be checked.
+ */
+ for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); prod_index++)
+ if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe)
+ break;
+
+ /* Now sweep backwards through the CQ, removing CQ entries
+ * that match our QP by copying older entries on top of them.
+ */
+ while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) {
+ cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
+ cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+ if (is_equal_rsn(cqe64, srq, rsn)) {
+ if (srq)
+ mlx5_ib_free_srq_wqe(srq, be16_to_cpu(cqe64->wqe_counter));
+ ++nfreed;
+ } else if (nfreed) {
+ dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe);
+ dest64 = (cq->mcq.cqe_sz == 64) ? dest : dest + 64;
+ owner_bit = dest64->op_own & MLX5_CQE_OWNER_MASK;
+ memcpy(dest, cqe, cq->mcq.cqe_sz);
+ dest64->op_own = owner_bit |
+ (dest64->op_own & ~MLX5_CQE_OWNER_MASK);
+ }
+ }
+
+ if (nfreed) {
+ cq->mcq.cons_index += nfreed;
+ /* Make sure update of buffer contents is done before
+ * updating consumer index.
+ */
+ wmb();
+ mlx5_cq_set_ci(&cq->mcq);
+ }
+}
+
+void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq)
+{
+ if (!cq)
+ return;
+
+ spin_lock_irq(&cq->lock);
+ __mlx5_ib_cq_clean(cq, qpn, srq);
+ spin_unlock_irq(&cq->lock);
+}
+
+int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
+{
+ return -ENOSYS;
+}
+
+int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+ return -ENOSYS;
+}
+
+int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq)
+{
+ struct mlx5_ib_cq *cq;
+
+ if (!ibcq)
+ return 128;
+
+ cq = to_mcq(ibcq);
+ return cq->cqe_size;
+}
diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c
new file mode 100644
index 000000000000..256a23344f28
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/doorbell.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kref.h>
+#include <linux/slab.h>
+#include <rdma/ib_umem.h>
+
+#include "mlx5_ib.h"
+
+struct mlx5_ib_user_db_page {
+ struct list_head list;
+ struct ib_umem *umem;
+ unsigned long user_virt;
+ int refcnt;
+};
+
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
+ struct mlx5_db *db)
+{
+ struct mlx5_ib_user_db_page *page;
+ struct ib_umem_chunk *chunk;
+ int err = 0;
+
+ mutex_lock(&context->db_page_mutex);
+
+ list_for_each_entry(page, &context->db_page_list, list)
+ if (page->user_virt == (virt & PAGE_MASK))
+ goto found;
+
+ page = kmalloc(sizeof(*page), GFP_KERNEL);
+ if (!page) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ page->user_virt = (virt & PAGE_MASK);
+ page->refcnt = 0;
+ page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
+ PAGE_SIZE, 0, 0);
+ if (IS_ERR(page->umem)) {
+ err = PTR_ERR(page->umem);
+ kfree(page);
+ goto out;
+ }
+
+ list_add(&page->list, &context->db_page_list);
+
+found:
+ chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
+ db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
+ db->u.user_page = page;
+ ++page->refcnt;
+
+out:
+ mutex_unlock(&context->db_page_mutex);
+
+ return err;
+}
+
+void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db)
+{
+ mutex_lock(&context->db_page_mutex);
+
+ if (!--db->u.user_page->refcnt) {
+ list_del(&db->u.user_page->list);
+ ib_umem_release(db->u.user_page->umem);
+ kfree(db->u.user_page);
+ }
+
+ mutex_unlock(&context->db_page_mutex);
+}
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
new file mode 100644
index 000000000000..5c8938be0e08
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/mad.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
+#include "mlx5_ib.h"
+
+enum {
+ MLX5_IB_VENDOR_CLASS1 = 0x9,
+ MLX5_IB_VENDOR_CLASS2 = 0xa
+};
+
+int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+ void *in_mad, void *response_mad)
+{
+ u8 op_modifier = 0;
+
+ /* Key check traps can't be generated unless we have in_wc to
+ * tell us where to send the trap.
+ */
+ if (ignore_mkey || !in_wc)
+ op_modifier |= 0x1;
+ if (ignore_bkey || !in_wc)
+ op_modifier |= 0x2;
+
+ return mlx5_core_mad_ifc(&dev->mdev, in_mad, response_mad, op_modifier, port);
+}
+
+int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+ struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ u16 slid;
+ int err;
+
+ slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
+
+ if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0)
+ return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+
+ if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+ in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+ if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
+ in_mad->mad_hdr.method != IB_MGMT_METHOD_SET &&
+ in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS)
+ return IB_MAD_RESULT_SUCCESS;
+
+ /* Don't process SMInfo queries -- the SMA can't handle them.
+ */
+ if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
+ return IB_MAD_RESULT_SUCCESS;
+ } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
+ in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS1 ||
+ in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS2 ||
+ in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
+ if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
+ in_mad->mad_hdr.method != IB_MGMT_METHOD_SET)
+ return IB_MAD_RESULT_SUCCESS;
+ } else {
+ return IB_MAD_RESULT_SUCCESS;
+ }
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev),
+ mad_flags & IB_MAD_IGNORE_MKEY,
+ mad_flags & IB_MAD_IGNORE_BKEY,
+ port_num, in_wc, in_grh, in_mad, out_mad);
+ if (err)
+ return IB_MAD_RESULT_FAILURE;
+
+ /* set return bit in status of directed route responses */
+ if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+ out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
+
+ if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
+ /* no response for trap repress */
+ return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+
+ return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+ u16 packet_error;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+
+ packet_error = be16_to_cpu(out_mad->status);
+
+ dev->mdev.caps.ext_port_cap[port - 1] = (!err && !packet_error) ?
+ MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0;
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
new file mode 100644
index 000000000000..8000fff4d444
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -0,0 +1,1504 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io-mapping.h>
+#include <linux/sched.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
+#include "user.h"
+#include "mlx5_ib.h"
+
+#define DRIVER_NAME "mlx5_ib"
+#define DRIVER_VERSION "1.0"
+#define DRIVER_RELDATE "June 2013"
+
+MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+static int prof_sel = 2;
+module_param_named(prof_sel, prof_sel, int, 0444);
+MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
+
+static char mlx5_version[] =
+ DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v"
+ DRIVER_VERSION " (" DRIVER_RELDATE ")\n";
+
+static struct mlx5_profile profile[] = {
+ [0] = {
+ .mask = 0,
+ },
+ [1] = {
+ .mask = MLX5_PROF_MASK_QP_SIZE,
+ .log_max_qp = 12,
+ },
+ [2] = {
+ .mask = MLX5_PROF_MASK_QP_SIZE |
+ MLX5_PROF_MASK_MR_CACHE,
+ .log_max_qp = 17,
+ .mr_cache[0] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[1] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[2] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[3] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[4] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[5] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[6] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[7] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[8] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[9] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[10] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[11] = {
+ .size = 500,
+ .limit = 250
+ },
+ .mr_cache[12] = {
+ .size = 64,
+ .limit = 32
+ },
+ .mr_cache[13] = {
+ .size = 32,
+ .limit = 16
+ },
+ .mr_cache[14] = {
+ .size = 16,
+ .limit = 8
+ },
+ .mr_cache[15] = {
+ .size = 8,
+ .limit = 4
+ },
+ },
+};
+
+int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn)
+{
+ struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+ struct mlx5_eq *eq, *n;
+ int err = -ENOENT;
+
+ spin_lock(&table->lock);
+ list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+ if (eq->index == vector) {
+ *eqn = eq->eqn;
+ *irqn = eq->irqn;
+ err = 0;
+ break;
+ }
+ }
+ spin_unlock(&table->lock);
+
+ return err;
+}
+
+static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+ struct mlx5_eq *eq, *n;
+ int ncomp_vec;
+ int nent;
+ int err;
+ int i;
+
+ INIT_LIST_HEAD(&dev->eqs_list);
+ ncomp_vec = table->num_comp_vectors;
+ nent = MLX5_COMP_EQ_SIZE;
+ for (i = 0; i < ncomp_vec; i++) {
+ eq = kzalloc(sizeof(*eq), GFP_KERNEL);
+ if (!eq) {
+ err = -ENOMEM;
+ goto clean;
+ }
+
+ snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
+ err = mlx5_create_map_eq(&dev->mdev, eq,
+ i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
+ eq->name,
+ &dev->mdev.priv.uuari.uars[0]);
+ if (err) {
+ kfree(eq);
+ goto clean;
+ }
+ mlx5_ib_dbg(dev, "allocated completion EQN %d\n", eq->eqn);
+ eq->index = i;
+ spin_lock(&table->lock);
+ list_add_tail(&eq->list, &dev->eqs_list);
+ spin_unlock(&table->lock);
+ }
+
+ dev->num_comp_vectors = ncomp_vec;
+ return 0;
+
+clean:
+ spin_lock(&table->lock);
+ list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+ list_del(&eq->list);
+ spin_unlock(&table->lock);
+ if (mlx5_destroy_unmap_eq(&dev->mdev, eq))
+ mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn);
+ kfree(eq);
+ spin_lock(&table->lock);
+ }
+ spin_unlock(&table->lock);
+ return err;
+}
+
+static void free_comp_eqs(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+ struct mlx5_eq *eq, *n;
+
+ spin_lock(&table->lock);
+ list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+ list_del(&eq->list);
+ spin_unlock(&table->lock);
+ if (mlx5_destroy_unmap_eq(&dev->mdev, eq))
+ mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn);
+ kfree(eq);
+ spin_lock(&table->lock);
+ }
+ spin_unlock(&table->lock);
+}
+
+static int mlx5_ib_query_device(struct ib_device *ibdev,
+ struct ib_device_attr *props)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+ int max_rq_sg;
+ int max_sq_sg;
+ u64 flags;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memset(props, 0, sizeof(*props));
+
+ props->fw_ver = ((u64)fw_rev_maj(&dev->mdev) << 32) |
+ (fw_rev_min(&dev->mdev) << 16) |
+ fw_rev_sub(&dev->mdev);
+ props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |
+ IB_DEVICE_PORT_ACTIVE_EVENT |
+ IB_DEVICE_SYS_IMAGE_GUID |
+ IB_DEVICE_RC_RNR_NAK_GEN |
+ IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
+ flags = dev->mdev.caps.flags;
+ if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR)
+ props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
+ if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR)
+ props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
+ if (flags & MLX5_DEV_CAP_FLAG_APM)
+ props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
+ props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY;
+ if (flags & MLX5_DEV_CAP_FLAG_XRC)
+ props->device_cap_flags |= IB_DEVICE_XRC;
+ props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
+
+ props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) &
+ 0xffffff;
+ props->vendor_part_id = be16_to_cpup((__be16 *)(out_mad->data + 30));
+ props->hw_ver = be32_to_cpup((__be32 *)(out_mad->data + 32));
+ memcpy(&props->sys_image_guid, out_mad->data + 4, 8);
+
+ props->max_mr_size = ~0ull;
+ props->page_size_cap = dev->mdev.caps.min_page_sz;
+ props->max_qp = 1 << dev->mdev.caps.log_max_qp;
+ props->max_qp_wr = dev->mdev.caps.max_wqes;
+ max_rq_sg = dev->mdev.caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg);
+ max_sq_sg = (dev->mdev.caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) /
+ sizeof(struct mlx5_wqe_data_seg);
+ props->max_sge = min(max_rq_sg, max_sq_sg);
+ props->max_cq = 1 << dev->mdev.caps.log_max_cq;
+ props->max_cqe = dev->mdev.caps.max_cqes - 1;
+ props->max_mr = 1 << dev->mdev.caps.log_max_mkey;
+ props->max_pd = 1 << dev->mdev.caps.log_max_pd;
+ props->max_qp_rd_atom = dev->mdev.caps.max_ra_req_qp;
+ props->max_qp_init_rd_atom = dev->mdev.caps.max_ra_res_qp;
+ props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp;
+ props->max_srq = 1 << dev->mdev.caps.log_max_srq;
+ props->max_srq_wr = dev->mdev.caps.max_srq_wqes - 1;
+ props->max_srq_sge = max_rq_sg - 1;
+ props->max_fast_reg_page_list_len = (unsigned int)-1;
+ props->local_ca_ack_delay = dev->mdev.caps.local_ca_ack_delay;
+ props->atomic_cap = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ?
+ IB_ATOMIC_HCA : IB_ATOMIC_NONE;
+ props->masked_atomic_cap = IB_ATOMIC_HCA;
+ props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28));
+ props->max_mcast_grp = 1 << dev->mdev.caps.log_max_mcg;
+ props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg;
+ props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+ props->max_mcast_grp;
+ props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+
+ return err;
+}
+
+int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int ext_active_speed;
+ int err = -ENOMEM;
+
+ if (port < 1 || port > dev->mdev.caps.num_ports) {
+ mlx5_ib_warn(dev, "invalid port number %d\n", port);
+ return -EINVAL;
+ }
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ memset(props, 0, sizeof(*props));
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err) {
+ mlx5_ib_warn(dev, "err %d\n", err);
+ goto out;
+ }
+
+
+ props->lid = be16_to_cpup((__be16 *)(out_mad->data + 16));
+ props->lmc = out_mad->data[34] & 0x7;
+ props->sm_lid = be16_to_cpup((__be16 *)(out_mad->data + 18));
+ props->sm_sl = out_mad->data[36] & 0xf;
+ props->state = out_mad->data[32] & 0xf;
+ props->phys_state = out_mad->data[33] >> 4;
+ props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20));
+ props->gid_tbl_len = out_mad->data[50];
+ props->max_msg_sz = 1 << to_mdev(ibdev)->mdev.caps.log_max_msg;
+ props->pkey_tbl_len = to_mdev(ibdev)->mdev.caps.port[port - 1].pkey_table_len;
+ props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46));
+ props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48));
+ props->active_width = out_mad->data[31] & 0xf;
+ props->active_speed = out_mad->data[35] >> 4;
+ props->max_mtu = out_mad->data[41] & 0xf;
+ props->active_mtu = out_mad->data[36] >> 4;
+ props->subnet_timeout = out_mad->data[51] & 0x1f;
+ props->max_vl_num = out_mad->data[37] >> 4;
+ props->init_type_reply = out_mad->data[41] >> 4;
+
+ /* Check if extended speeds (EDR/FDR/...) are supported */
+ if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
+ ext_active_speed = out_mad->data[62] >> 4;
+
+ switch (ext_active_speed) {
+ case 1:
+ props->active_speed = 16; /* FDR */
+ break;
+ case 2:
+ props->active_speed = 32; /* EDR */
+ break;
+ }
+ }
+
+ /* If reported active speed is QDR, check if is FDR-10 */
+ if (props->active_speed == 4) {
+ if (dev->mdev.caps.ext_port_cap[port - 1] &
+ MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
+ init_query_mad(in_mad);
+ in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(dev, 1, 1, port,
+ NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ /* Checking LinkSpeedActive for FDR-10 */
+ if (out_mad->data[15] & 0x1)
+ props->active_speed = 8;
+ }
+ }
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+
+ return err;
+}
+
+static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(gid->raw, out_mad->data + 8, 8);
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_GUID_INFO;
+ in_mad->attr_mod = cpu_to_be32(index / 8);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+static int mlx5_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE;
+ in_mad->attr_mod = cpu_to_be32(index / 32);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]);
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+struct mlx5_reg_node_desc {
+ u8 desc[64];
+};
+
+static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask,
+ struct ib_device_modify *props)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_reg_node_desc in;
+ struct mlx5_reg_node_desc out;
+ int err;
+
+ if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+ return -EOPNOTSUPP;
+
+ if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+ return 0;
+
+ /*
+ * If possible, pass node desc to FW, so it can generate
+ * a 144 trap. If cmd fails, just ignore.
+ */
+ memcpy(&in, props->node_desc, 64);
+ err = mlx5_core_access_reg(&dev->mdev, &in, sizeof(in), &out,
+ sizeof(out), MLX5_REG_NODE_DESC, 0, 1);
+ if (err)
+ return err;
+
+ memcpy(ibdev->node_desc, props->node_desc, 64);
+
+ return err;
+}
+
+static int mlx5_ib_modify_port(struct ib_device *ibdev, u8 port, int mask,
+ struct ib_port_modify *props)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct ib_port_attr attr;
+ u32 tmp;
+ int err;
+
+ mutex_lock(&dev->cap_mask_mutex);
+
+ err = mlx5_ib_query_port(ibdev, port, &attr);
+ if (err)
+ goto out;
+
+ tmp = (attr.port_cap_flags | props->set_port_cap_mask) &
+ ~props->clr_port_cap_mask;
+
+ err = mlx5_set_port_caps(&dev->mdev, port, tmp);
+
+out:
+ mutex_unlock(&dev->cap_mask_mutex);
+ return err;
+}
+
+static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_ib_alloc_ucontext_req req;
+ struct mlx5_ib_alloc_ucontext_resp resp;
+ struct mlx5_ib_ucontext *context;
+ struct mlx5_uuar_info *uuari;
+ struct mlx5_uar *uars;
+ int num_uars;
+ int uuarn;
+ int err;
+ int i;
+
+ if (!dev->ib_active)
+ return ERR_PTR(-EAGAIN);
+
+ err = ib_copy_from_udata(&req, udata, sizeof(req));
+ if (err)
+ return ERR_PTR(err);
+
+ if (req.total_num_uuars > MLX5_MAX_UUARS)
+ return ERR_PTR(-ENOMEM);
+
+ if (req.total_num_uuars == 0)
+ return ERR_PTR(-EINVAL);
+
+ req.total_num_uuars = ALIGN(req.total_num_uuars, MLX5_BF_REGS_PER_PAGE);
+ if (req.num_low_latency_uuars > req.total_num_uuars - 1)
+ return ERR_PTR(-EINVAL);
+
+ num_uars = req.total_num_uuars / MLX5_BF_REGS_PER_PAGE;
+ resp.qp_tab_size = 1 << dev->mdev.caps.log_max_qp;
+ resp.bf_reg_size = dev->mdev.caps.bf_reg_size;
+ resp.cache_line_size = L1_CACHE_BYTES;
+ resp.max_sq_desc_sz = dev->mdev.caps.max_sq_desc_sz;
+ resp.max_rq_desc_sz = dev->mdev.caps.max_rq_desc_sz;
+ resp.max_send_wqebb = dev->mdev.caps.max_wqes;
+ resp.max_recv_wr = dev->mdev.caps.max_wqes;
+ resp.max_srq_recv_wr = dev->mdev.caps.max_srq_wqes;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ uuari = &context->uuari;
+ mutex_init(&uuari->lock);
+ uars = kcalloc(num_uars, sizeof(*uars), GFP_KERNEL);
+ if (!uars) {
+ err = -ENOMEM;
+ goto out_ctx;
+ }
+
+ uuari->bitmap = kcalloc(BITS_TO_LONGS(req.total_num_uuars),
+ sizeof(*uuari->bitmap),
+ GFP_KERNEL);
+ if (!uuari->bitmap) {
+ err = -ENOMEM;
+ goto out_uar_ctx;
+ }
+ /*
+ * clear all fast path uuars
+ */
+ for (i = 0; i < req.total_num_uuars; i++) {
+ uuarn = i & 3;
+ if (uuarn == 2 || uuarn == 3)
+ set_bit(i, uuari->bitmap);
+ }
+
+ uuari->count = kcalloc(req.total_num_uuars, sizeof(*uuari->count), GFP_KERNEL);
+ if (!uuari->count) {
+ err = -ENOMEM;
+ goto out_bitmap;
+ }
+
+ for (i = 0; i < num_uars; i++) {
+ err = mlx5_cmd_alloc_uar(&dev->mdev, &uars[i].index);
+ if (err)
+ goto out_count;
+ }
+
+ INIT_LIST_HEAD(&context->db_page_list);
+ mutex_init(&context->db_page_mutex);
+
+ resp.tot_uuars = req.total_num_uuars;
+ resp.num_ports = dev->mdev.caps.num_ports;
+ err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ if (err)
+ goto out_uars;
+
+ uuari->num_low_latency_uuars = req.num_low_latency_uuars;
+ uuari->uars = uars;
+ uuari->num_uars = num_uars;
+ return &context->ibucontext;
+
+out_uars:
+ for (i--; i >= 0; i--)
+ mlx5_cmd_free_uar(&dev->mdev, uars[i].index);
+out_count:
+ kfree(uuari->count);
+
+out_bitmap:
+ kfree(uuari->bitmap);
+
+out_uar_ctx:
+ kfree(uars);
+
+out_ctx:
+ kfree(context);
+ return ERR_PTR(err);
+}
+
+static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+ struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
+ struct mlx5_ib_dev *dev = to_mdev(ibcontext->device);
+ struct mlx5_uuar_info *uuari = &context->uuari;
+ int i;
+
+ for (i = 0; i < uuari->num_uars; i++) {
+ if (mlx5_cmd_free_uar(&dev->mdev, uuari->uars[i].index))
+ mlx5_ib_warn(dev, "failed to free UAR 0x%x\n", uuari->uars[i].index);
+ }
+
+ kfree(uuari->count);
+ kfree(uuari->bitmap);
+ kfree(uuari->uars);
+ kfree(context);
+
+ return 0;
+}
+
+static phys_addr_t uar_index2pfn(struct mlx5_ib_dev *dev, int index)
+{
+ return (pci_resource_start(dev->mdev.pdev, 0) >> PAGE_SHIFT) + index;
+}
+
+static int get_command(unsigned long offset)
+{
+ return (offset >> MLX5_IB_MMAP_CMD_SHIFT) & MLX5_IB_MMAP_CMD_MASK;
+}
+
+static int get_arg(unsigned long offset)
+{
+ return offset & ((1 << MLX5_IB_MMAP_CMD_SHIFT) - 1);
+}
+
+static int get_index(unsigned long offset)
+{
+ return get_arg(offset);
+}
+
+static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
+{
+ struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
+ struct mlx5_ib_dev *dev = to_mdev(ibcontext->device);
+ struct mlx5_uuar_info *uuari = &context->uuari;
+ unsigned long command;
+ unsigned long idx;
+ phys_addr_t pfn;
+
+ command = get_command(vma->vm_pgoff);
+ switch (command) {
+ case MLX5_IB_MMAP_REGULAR_PAGE:
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ idx = get_index(vma->vm_pgoff);
+ pfn = uar_index2pfn(dev, uuari->uars[idx].index);
+ mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn 0x%llx\n", idx,
+ (unsigned long long)pfn);
+
+ if (idx >= uuari->num_uars)
+ return -EINVAL;
+
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ if (io_remap_pfn_range(vma, vma->vm_start, pfn,
+ PAGE_SIZE, vma->vm_page_prot))
+ return -EAGAIN;
+
+ mlx5_ib_dbg(dev, "mapped WC at 0x%lx, PA 0x%llx\n",
+ vma->vm_start,
+ (unsigned long long)pfn << PAGE_SHIFT);
+ break;
+
+ case MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES:
+ return -ENOSYS;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int alloc_pa_mkey(struct mlx5_ib_dev *dev, u32 *key, u32 pdn)
+{
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_mkey_seg *seg;
+ struct mlx5_core_mr mr;
+ int err;
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ seg = &in->seg;
+ seg->flags = MLX5_PERM_LOCAL_READ | MLX5_ACCESS_MODE_PA;
+ seg->flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64);
+ seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ seg->start_addr = 0;
+
+ err = mlx5_core_create_mkey(&dev->mdev, &mr, in, sizeof(*in));
+ if (err) {
+ mlx5_ib_warn(dev, "failed to create mkey, %d\n", err);
+ goto err_in;
+ }
+
+ kfree(in);
+ *key = mr.key;
+
+ return 0;
+
+err_in:
+ kfree(in);
+
+ return err;
+}
+
+static void free_pa_mkey(struct mlx5_ib_dev *dev, u32 key)
+{
+ struct mlx5_core_mr mr;
+ int err;
+
+ memset(&mr, 0, sizeof(mr));
+ mr.key = key;
+ err = mlx5_core_destroy_mkey(&dev->mdev, &mr);
+ if (err)
+ mlx5_ib_warn(dev, "failed to destroy mkey 0x%x\n", key);
+}
+
+static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_alloc_pd_resp resp;
+ struct mlx5_ib_pd *pd;
+ int err;
+
+ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx5_core_alloc_pd(&to_mdev(ibdev)->mdev, &pd->pdn);
+ if (err) {
+ kfree(pd);
+ return ERR_PTR(err);
+ }
+
+ if (context) {
+ resp.pdn = pd->pdn;
+ if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
+ mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn);
+ kfree(pd);
+ return ERR_PTR(-EFAULT);
+ }
+ } else {
+ err = alloc_pa_mkey(to_mdev(ibdev), &pd->pa_lkey, pd->pdn);
+ if (err) {
+ mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn);
+ kfree(pd);
+ return ERR_PTR(err);
+ }
+ }
+
+ return &pd->ibpd;
+}
+
+static int mlx5_ib_dealloc_pd(struct ib_pd *pd)
+{
+ struct mlx5_ib_dev *mdev = to_mdev(pd->device);
+ struct mlx5_ib_pd *mpd = to_mpd(pd);
+
+ if (!pd->uobject)
+ free_pa_mkey(mdev, mpd->pa_lkey);
+
+ mlx5_core_dealloc_pd(&mdev->mdev, mpd->pdn);
+ kfree(mpd);
+
+ return 0;
+}
+
+static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ int err;
+
+ err = mlx5_core_attach_mcg(&dev->mdev, gid, ibqp->qp_num);
+ if (err)
+ mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n",
+ ibqp->qp_num, gid->raw);
+
+ return err;
+}
+
+static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ int err;
+
+ err = mlx5_core_detach_mcg(&dev->mdev, gid, ibqp->qp_num);
+ if (err)
+ mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n",
+ ibqp->qp_num, gid->raw);
+
+ return err;
+}
+
+static int init_node_data(struct mlx5_ib_dev *dev)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+ err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
+ in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+ err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ dev->mdev.rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32));
+ memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+
+ return sprintf(buf, "%d\n", dev->mdev.priv.fw_pages);
+}
+
+static ssize_t show_reg_pages(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+
+ return sprintf(buf, "%d\n", dev->mdev.priv.reg_pages);
+}
+
+static ssize_t show_hca(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+ return sprintf(buf, "MT%d\n", dev->mdev.pdev->device);
+}
+
+static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+ return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(&dev->mdev),
+ fw_rev_min(&dev->mdev), fw_rev_sub(&dev->mdev));
+}
+
+static ssize_t show_rev(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+ return sprintf(buf, "%x\n", dev->mdev.rev_id);
+}
+
+static ssize_t show_board(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx5_ib_dev *dev =
+ container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+ return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN,
+ dev->mdev.board_id);
+}
+
+static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static DEVICE_ATTR(fw_pages, S_IRUGO, show_fw_pages, NULL);
+static DEVICE_ATTR(reg_pages, S_IRUGO, show_reg_pages, NULL);
+
+static struct device_attribute *mlx5_class_attributes[] = {
+ &dev_attr_hw_rev,
+ &dev_attr_fw_ver,
+ &dev_attr_hca_type,
+ &dev_attr_board_id,
+ &dev_attr_fw_pages,
+ &dev_attr_reg_pages,
+};
+
+static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
+ void *data)
+{
+ struct mlx5_ib_dev *ibdev = container_of(dev, struct mlx5_ib_dev, mdev);
+ struct ib_event ibev;
+ u8 port = 0;
+
+ switch (event) {
+ case MLX5_DEV_EVENT_SYS_ERROR:
+ ibdev->ib_active = false;
+ ibev.event = IB_EVENT_DEVICE_FATAL;
+ break;
+
+ case MLX5_DEV_EVENT_PORT_UP:
+ ibev.event = IB_EVENT_PORT_ACTIVE;
+ port = *(u8 *)data;
+ break;
+
+ case MLX5_DEV_EVENT_PORT_DOWN:
+ ibev.event = IB_EVENT_PORT_ERR;
+ port = *(u8 *)data;
+ break;
+
+ case MLX5_DEV_EVENT_PORT_INITIALIZED:
+ /* not used by ULPs */
+ return;
+
+ case MLX5_DEV_EVENT_LID_CHANGE:
+ ibev.event = IB_EVENT_LID_CHANGE;
+ port = *(u8 *)data;
+ break;
+
+ case MLX5_DEV_EVENT_PKEY_CHANGE:
+ ibev.event = IB_EVENT_PKEY_CHANGE;
+ port = *(u8 *)data;
+ break;
+
+ case MLX5_DEV_EVENT_GUID_CHANGE:
+ ibev.event = IB_EVENT_GID_CHANGE;
+ port = *(u8 *)data;
+ break;
+
+ case MLX5_DEV_EVENT_CLIENT_REREG:
+ ibev.event = IB_EVENT_CLIENT_REREGISTER;
+ port = *(u8 *)data;
+ break;
+ }
+
+ ibev.device = &ibdev->ib_dev;
+ ibev.element.port_num = port;
+
+ if (ibdev->ib_active)
+ ib_dispatch_event(&ibev);
+}
+
+static void get_ext_port_caps(struct mlx5_ib_dev *dev)
+{
+ int port;
+
+ for (port = 1; port <= dev->mdev.caps.num_ports; port++)
+ mlx5_query_ext_port_caps(dev, port);
+}
+
+static int get_port_caps(struct mlx5_ib_dev *dev)
+{
+ struct ib_device_attr *dprops = NULL;
+ struct ib_port_attr *pprops = NULL;
+ int err = 0;
+ int port;
+
+ pprops = kmalloc(sizeof(*pprops), GFP_KERNEL);
+ if (!pprops)
+ goto out;
+
+ dprops = kmalloc(sizeof(*dprops), GFP_KERNEL);
+ if (!dprops)
+ goto out;
+
+ err = mlx5_ib_query_device(&dev->ib_dev, dprops);
+ if (err) {
+ mlx5_ib_warn(dev, "query_device failed %d\n", err);
+ goto out;
+ }
+
+ for (port = 1; port <= dev->mdev.caps.num_ports; port++) {
+ err = mlx5_ib_query_port(&dev->ib_dev, port, pprops);
+ if (err) {
+ mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err);
+ break;
+ }
+ dev->mdev.caps.port[port - 1].pkey_table_len = dprops->max_pkeys;
+ dev->mdev.caps.port[port - 1].gid_table_len = pprops->gid_tbl_len;
+ mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n",
+ dprops->max_pkeys, pprops->gid_tbl_len);
+ }
+
+out:
+ kfree(pprops);
+ kfree(dprops);
+
+ return err;
+}
+
+static void destroy_umrc_res(struct mlx5_ib_dev *dev)
+{
+ int err;
+
+ err = mlx5_mr_cache_cleanup(dev);
+ if (err)
+ mlx5_ib_warn(dev, "mr cache cleanup failed\n");
+
+ mlx5_ib_destroy_qp(dev->umrc.qp);
+ ib_destroy_cq(dev->umrc.cq);
+ ib_dereg_mr(dev->umrc.mr);
+ ib_dealloc_pd(dev->umrc.pd);
+}
+
+enum {
+ MAX_UMR_WR = 128,
+};
+
+static int create_umr_res(struct mlx5_ib_dev *dev)
+{
+ struct ib_qp_init_attr *init_attr = NULL;
+ struct ib_qp_attr *attr = NULL;
+ struct ib_pd *pd;
+ struct ib_cq *cq;
+ struct ib_qp *qp;
+ struct ib_mr *mr;
+ int ret;
+
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
+ if (!attr || !init_attr) {
+ ret = -ENOMEM;
+ goto error_0;
+ }
+
+ pd = ib_alloc_pd(&dev->ib_dev);
+ if (IS_ERR(pd)) {
+ mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
+ ret = PTR_ERR(pd);
+ goto error_0;
+ }
+
+ mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(mr)) {
+ mlx5_ib_dbg(dev, "Couldn't create DMA MR for sync UMR QP\n");
+ ret = PTR_ERR(mr);
+ goto error_1;
+ }
+
+ cq = ib_create_cq(&dev->ib_dev, mlx5_umr_cq_handler, NULL, NULL, 128,
+ 0);
+ if (IS_ERR(cq)) {
+ mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n");
+ ret = PTR_ERR(cq);
+ goto error_2;
+ }
+ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+
+ init_attr->send_cq = cq;
+ init_attr->recv_cq = cq;
+ init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
+ init_attr->cap.max_send_wr = MAX_UMR_WR;
+ init_attr->cap.max_send_sge = 1;
+ init_attr->qp_type = MLX5_IB_QPT_REG_UMR;
+ init_attr->port_num = 1;
+ qp = mlx5_ib_create_qp(pd, init_attr, NULL);
+ if (IS_ERR(qp)) {
+ mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n");
+ ret = PTR_ERR(qp);
+ goto error_3;
+ }
+ qp->device = &dev->ib_dev;
+ qp->real_qp = qp;
+ qp->uobject = NULL;
+ qp->qp_type = MLX5_IB_QPT_REG_UMR;
+
+ attr->qp_state = IB_QPS_INIT;
+ attr->port_num = 1;
+ ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_PKEY_INDEX |
+ IB_QP_PORT, NULL);
+ if (ret) {
+ mlx5_ib_dbg(dev, "Couldn't modify UMR QP\n");
+ goto error_4;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+ attr->qp_state = IB_QPS_RTR;
+ attr->path_mtu = IB_MTU_256;
+
+ ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL);
+ if (ret) {
+ mlx5_ib_dbg(dev, "Couldn't modify umr QP to rtr\n");
+ goto error_4;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+ attr->qp_state = IB_QPS_RTS;
+ ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL);
+ if (ret) {
+ mlx5_ib_dbg(dev, "Couldn't modify umr QP to rts\n");
+ goto error_4;
+ }
+
+ dev->umrc.qp = qp;
+ dev->umrc.cq = cq;
+ dev->umrc.mr = mr;
+ dev->umrc.pd = pd;
+
+ sema_init(&dev->umrc.sem, MAX_UMR_WR);
+ ret = mlx5_mr_cache_init(dev);
+ if (ret) {
+ mlx5_ib_warn(dev, "mr cache init failed %d\n", ret);
+ goto error_4;
+ }
+
+ kfree(attr);
+ kfree(init_attr);
+
+ return 0;
+
+error_4:
+ mlx5_ib_destroy_qp(qp);
+
+error_3:
+ ib_destroy_cq(cq);
+
+error_2:
+ ib_dereg_mr(mr);
+
+error_1:
+ ib_dealloc_pd(pd);
+
+error_0:
+ kfree(attr);
+ kfree(init_attr);
+ return ret;
+}
+
+static int create_dev_resources(struct mlx5_ib_resources *devr)
+{
+ struct ib_srq_init_attr attr;
+ struct mlx5_ib_dev *dev;
+ int ret = 0;
+
+ dev = container_of(devr, struct mlx5_ib_dev, devr);
+
+ devr->p0 = mlx5_ib_alloc_pd(&dev->ib_dev, NULL, NULL);
+ if (IS_ERR(devr->p0)) {
+ ret = PTR_ERR(devr->p0);
+ goto error0;
+ }
+ devr->p0->device = &dev->ib_dev;
+ devr->p0->uobject = NULL;
+ atomic_set(&devr->p0->usecnt, 0);
+
+ devr->c0 = mlx5_ib_create_cq(&dev->ib_dev, 1, 0, NULL, NULL);
+ if (IS_ERR(devr->c0)) {
+ ret = PTR_ERR(devr->c0);
+ goto error1;
+ }
+ devr->c0->device = &dev->ib_dev;
+ devr->c0->uobject = NULL;
+ devr->c0->comp_handler = NULL;
+ devr->c0->event_handler = NULL;
+ devr->c0->cq_context = NULL;
+ atomic_set(&devr->c0->usecnt, 0);
+
+ devr->x0 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL);
+ if (IS_ERR(devr->x0)) {
+ ret = PTR_ERR(devr->x0);
+ goto error2;
+ }
+ devr->x0->device = &dev->ib_dev;
+ devr->x0->inode = NULL;
+ atomic_set(&devr->x0->usecnt, 0);
+ mutex_init(&devr->x0->tgt_qp_mutex);
+ INIT_LIST_HEAD(&devr->x0->tgt_qp_list);
+
+ devr->x1 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL);
+ if (IS_ERR(devr->x1)) {
+ ret = PTR_ERR(devr->x1);
+ goto error3;
+ }
+ devr->x1->device = &dev->ib_dev;
+ devr->x1->inode = NULL;
+ atomic_set(&devr->x1->usecnt, 0);
+ mutex_init(&devr->x1->tgt_qp_mutex);
+ INIT_LIST_HEAD(&devr->x1->tgt_qp_list);
+
+ memset(&attr, 0, sizeof(attr));
+ attr.attr.max_sge = 1;
+ attr.attr.max_wr = 1;
+ attr.srq_type = IB_SRQT_XRC;
+ attr.ext.xrc.cq = devr->c0;
+ attr.ext.xrc.xrcd = devr->x0;
+
+ devr->s0 = mlx5_ib_create_srq(devr->p0, &attr, NULL);
+ if (IS_ERR(devr->s0)) {
+ ret = PTR_ERR(devr->s0);
+ goto error4;
+ }
+ devr->s0->device = &dev->ib_dev;
+ devr->s0->pd = devr->p0;
+ devr->s0->uobject = NULL;
+ devr->s0->event_handler = NULL;
+ devr->s0->srq_context = NULL;
+ devr->s0->srq_type = IB_SRQT_XRC;
+ devr->s0->ext.xrc.xrcd = devr->x0;
+ devr->s0->ext.xrc.cq = devr->c0;
+ atomic_inc(&devr->s0->ext.xrc.xrcd->usecnt);
+ atomic_inc(&devr->s0->ext.xrc.cq->usecnt);
+ atomic_inc(&devr->p0->usecnt);
+ atomic_set(&devr->s0->usecnt, 0);
+
+ return 0;
+
+error4:
+ mlx5_ib_dealloc_xrcd(devr->x1);
+error3:
+ mlx5_ib_dealloc_xrcd(devr->x0);
+error2:
+ mlx5_ib_destroy_cq(devr->c0);
+error1:
+ mlx5_ib_dealloc_pd(devr->p0);
+error0:
+ return ret;
+}
+
+static void destroy_dev_resources(struct mlx5_ib_resources *devr)
+{
+ mlx5_ib_destroy_srq(devr->s0);
+ mlx5_ib_dealloc_xrcd(devr->x0);
+ mlx5_ib_dealloc_xrcd(devr->x1);
+ mlx5_ib_destroy_cq(devr->c0);
+ mlx5_ib_dealloc_pd(devr->p0);
+}
+
+static int init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct mlx5_core_dev *mdev;
+ struct mlx5_ib_dev *dev;
+ int err;
+ int i;
+
+ printk_once(KERN_INFO "%s", mlx5_version);
+
+ dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+
+ mdev = &dev->mdev;
+ mdev->event = mlx5_ib_event;
+ if (prof_sel >= ARRAY_SIZE(profile)) {
+ pr_warn("selected pofile out of range, selceting default\n");
+ prof_sel = 0;
+ }
+ mdev->profile = &profile[prof_sel];
+ err = mlx5_dev_init(mdev, pdev);
+ if (err)
+ goto err_free;
+
+ err = get_port_caps(dev);
+ if (err)
+ goto err_cleanup;
+
+ get_ext_port_caps(dev);
+
+ err = alloc_comp_eqs(dev);
+ if (err)
+ goto err_cleanup;
+
+ MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock);
+
+ strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX);
+ dev->ib_dev.owner = THIS_MODULE;
+ dev->ib_dev.node_type = RDMA_NODE_IB_CA;
+ dev->ib_dev.local_dma_lkey = mdev->caps.reserved_lkey;
+ dev->num_ports = mdev->caps.num_ports;
+ dev->ib_dev.phys_port_cnt = dev->num_ports;
+ dev->ib_dev.num_comp_vectors = dev->num_comp_vectors;
+ dev->ib_dev.dma_device = &mdev->pdev->dev;
+
+ dev->ib_dev.uverbs_abi_ver = MLX5_IB_UVERBS_ABI_VERSION;
+ dev->ib_dev.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) |
+ (1ull << IB_USER_VERBS_CMD_OPEN_QP);
+
+ dev->ib_dev.query_device = mlx5_ib_query_device;
+ dev->ib_dev.query_port = mlx5_ib_query_port;
+ dev->ib_dev.query_gid = mlx5_ib_query_gid;
+ dev->ib_dev.query_pkey = mlx5_ib_query_pkey;
+ dev->ib_dev.modify_device = mlx5_ib_modify_device;
+ dev->ib_dev.modify_port = mlx5_ib_modify_port;
+ dev->ib_dev.alloc_ucontext = mlx5_ib_alloc_ucontext;
+ dev->ib_dev.dealloc_ucontext = mlx5_ib_dealloc_ucontext;
+ dev->ib_dev.mmap = mlx5_ib_mmap;
+ dev->ib_dev.alloc_pd = mlx5_ib_alloc_pd;
+ dev->ib_dev.dealloc_pd = mlx5_ib_dealloc_pd;
+ dev->ib_dev.create_ah = mlx5_ib_create_ah;
+ dev->ib_dev.query_ah = mlx5_ib_query_ah;
+ dev->ib_dev.destroy_ah = mlx5_ib_destroy_ah;
+ dev->ib_dev.create_srq = mlx5_ib_create_srq;
+ dev->ib_dev.modify_srq = mlx5_ib_modify_srq;
+ dev->ib_dev.query_srq = mlx5_ib_query_srq;
+ dev->ib_dev.destroy_srq = mlx5_ib_destroy_srq;
+ dev->ib_dev.post_srq_recv = mlx5_ib_post_srq_recv;
+ dev->ib_dev.create_qp = mlx5_ib_create_qp;
+ dev->ib_dev.modify_qp = mlx5_ib_modify_qp;
+ dev->ib_dev.query_qp = mlx5_ib_query_qp;
+ dev->ib_dev.destroy_qp = mlx5_ib_destroy_qp;
+ dev->ib_dev.post_send = mlx5_ib_post_send;
+ dev->ib_dev.post_recv = mlx5_ib_post_recv;
+ dev->ib_dev.create_cq = mlx5_ib_create_cq;
+ dev->ib_dev.modify_cq = mlx5_ib_modify_cq;
+ dev->ib_dev.resize_cq = mlx5_ib_resize_cq;
+ dev->ib_dev.destroy_cq = mlx5_ib_destroy_cq;
+ dev->ib_dev.poll_cq = mlx5_ib_poll_cq;
+ dev->ib_dev.req_notify_cq = mlx5_ib_arm_cq;
+ dev->ib_dev.get_dma_mr = mlx5_ib_get_dma_mr;
+ dev->ib_dev.reg_user_mr = mlx5_ib_reg_user_mr;
+ dev->ib_dev.dereg_mr = mlx5_ib_dereg_mr;
+ dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach;
+ dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach;
+ dev->ib_dev.process_mad = mlx5_ib_process_mad;
+ dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr;
+ dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list;
+ dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list;
+
+ if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) {
+ dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
+ dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd;
+ dev->ib_dev.uverbs_cmd_mask |=
+ (1ull << IB_USER_VERBS_CMD_OPEN_XRCD) |
+ (1ull << IB_USER_VERBS_CMD_CLOSE_XRCD);
+ }
+
+ err = init_node_data(dev);
+ if (err)
+ goto err_eqs;
+
+ mutex_init(&dev->cap_mask_mutex);
+ spin_lock_init(&dev->mr_lock);
+
+ err = create_dev_resources(&dev->devr);
+ if (err)
+ goto err_eqs;
+
+ if (ib_register_device(&dev->ib_dev, NULL))
+ goto err_rsrc;
+
+ err = create_umr_res(dev);
+ if (err)
+ goto err_dev;
+
+ for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
+ if (device_create_file(&dev->ib_dev.dev,
+ mlx5_class_attributes[i]))
+ goto err_umrc;
+ }
+
+ dev->ib_active = true;
+
+ return 0;
+
+err_umrc:
+ destroy_umrc_res(dev);
+
+err_dev:
+ ib_unregister_device(&dev->ib_dev);
+
+err_rsrc:
+ destroy_dev_resources(&dev->devr);
+
+err_eqs:
+ free_comp_eqs(dev);
+
+err_cleanup:
+ mlx5_dev_cleanup(mdev);
+
+err_free:
+ ib_dealloc_device((struct ib_device *)dev);
+
+ return err;
+}
+
+static void remove_one(struct pci_dev *pdev)
+{
+ struct mlx5_ib_dev *dev = mlx5_pci2ibdev(pdev);
+
+ destroy_umrc_res(dev);
+ ib_unregister_device(&dev->ib_dev);
+ destroy_dev_resources(&dev->devr);
+ free_comp_eqs(dev);
+ mlx5_dev_cleanup(&dev->mdev);
+ ib_dealloc_device(&dev->ib_dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mlx5_ib_pci_table) = {
+ { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mlx5_ib_pci_table);
+
+static struct pci_driver mlx5_ib_driver = {
+ .name = DRIVER_NAME,
+ .id_table = mlx5_ib_pci_table,
+ .probe = init_one,
+ .remove = remove_one
+};
+
+static int __init mlx5_ib_init(void)
+{
+ return pci_register_driver(&mlx5_ib_driver);
+}
+
+static void __exit mlx5_ib_cleanup(void)
+{
+ pci_unregister_driver(&mlx5_ib_driver);
+}
+
+module_init(mlx5_ib_init);
+module_exit(mlx5_ib_cleanup);
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
new file mode 100644
index 000000000000..3a5322870b96
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/mem.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+
+/* @umem: umem object to scan
+ * @addr: ib virtual address requested by the user
+ * @count: number of PAGE_SIZE pages covered by umem
+ * @shift: page shift for the compound pages found in the region
+ * @ncont: number of compund pages
+ * @order: log2 of the number of compound pages
+ */
+void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
+ int *ncont, int *order)
+{
+ struct ib_umem_chunk *chunk;
+ unsigned long tmp;
+ unsigned long m;
+ int i, j, k;
+ u64 base = 0;
+ int p = 0;
+ int skip;
+ int mask;
+ u64 len;
+ u64 pfn;
+
+ addr = addr >> PAGE_SHIFT;
+ tmp = (unsigned long)addr;
+ m = find_first_bit(&tmp, sizeof(tmp));
+ skip = 1 << m;
+ mask = skip - 1;
+ i = 0;
+ list_for_each_entry(chunk, &umem->chunk_list, list)
+ for (j = 0; j < chunk->nmap; j++) {
+ len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
+ pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT;
+ for (k = 0; k < len; k++) {
+ if (!(i & mask)) {
+ tmp = (unsigned long)pfn;
+ m = min(m, find_first_bit(&tmp, sizeof(tmp)));
+ skip = 1 << m;
+ mask = skip - 1;
+ base = pfn;
+ p = 0;
+ } else {
+ if (base + p != pfn) {
+ tmp = (unsigned long)p;
+ m = find_first_bit(&tmp, sizeof(tmp));
+ skip = 1 << m;
+ mask = skip - 1;
+ base = pfn;
+ p = 0;
+ }
+ }
+ p++;
+ i++;
+ }
+ }
+
+ if (i) {
+ m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m);
+
+ if (order)
+ *order = ilog2(roundup_pow_of_two(i) >> m);
+
+ *ncont = DIV_ROUND_UP(i, (1 << m));
+ } else {
+ m = 0;
+
+ if (order)
+ *order = 0;
+
+ *ncont = 0;
+ }
+ *shift = PAGE_SHIFT + m;
+ *count = i;
+}
+
+void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
+ int page_shift, __be64 *pas, int umr)
+{
+ int shift = page_shift - PAGE_SHIFT;
+ int mask = (1 << shift) - 1;
+ struct ib_umem_chunk *chunk;
+ int i, j, k;
+ u64 cur = 0;
+ u64 base;
+ int len;
+
+ i = 0;
+ list_for_each_entry(chunk, &umem->chunk_list, list)
+ for (j = 0; j < chunk->nmap; j++) {
+ len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
+ base = sg_dma_address(&chunk->page_list[j]);
+ for (k = 0; k < len; k++) {
+ if (!(i & mask)) {
+ cur = base + (k << PAGE_SHIFT);
+ if (umr)
+ cur |= 3;
+
+ pas[i >> shift] = cpu_to_be64(cur);
+ mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n",
+ i >> shift, be64_to_cpu(pas[i >> shift]));
+ } else
+ mlx5_ib_dbg(dev, "=====> 0x%llx\n",
+ base + (k << PAGE_SHIFT));
+ i++;
+ }
+ }
+}
+
+int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset)
+{
+ u64 page_size;
+ u64 page_mask;
+ u64 off_size;
+ u64 off_mask;
+ u64 buf_off;
+
+ page_size = 1 << page_shift;
+ page_mask = page_size - 1;
+ buf_off = addr & page_mask;
+ off_size = page_size >> 6;
+ off_mask = off_size - 1;
+
+ if (buf_off & off_mask)
+ return -EINVAL;
+
+ *offset = buf_off >> ilog2(off_size);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
new file mode 100644
index 000000000000..836be9157242
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_IB_H
+#define MLX5_IB_H
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_smi.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/types.h>
+
+#define mlx5_ib_dbg(dev, format, arg...) \
+pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
+ __LINE__, current->pid, ##arg)
+
+#define mlx5_ib_err(dev, format, arg...) \
+pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
+ __LINE__, current->pid, ##arg)
+
+#define mlx5_ib_warn(dev, format, arg...) \
+pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
+ __LINE__, current->pid, ##arg)
+
+enum {
+ MLX5_IB_MMAP_CMD_SHIFT = 8,
+ MLX5_IB_MMAP_CMD_MASK = 0xff,
+};
+
+enum mlx5_ib_mmap_cmd {
+ MLX5_IB_MMAP_REGULAR_PAGE = 0,
+ MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES = 1, /* always last */
+};
+
+enum {
+ MLX5_RES_SCAT_DATA32_CQE = 0x1,
+ MLX5_RES_SCAT_DATA64_CQE = 0x2,
+ MLX5_REQ_SCAT_DATA32_CQE = 0x11,
+ MLX5_REQ_SCAT_DATA64_CQE = 0x22,
+};
+
+enum mlx5_ib_latency_class {
+ MLX5_IB_LATENCY_CLASS_LOW,
+ MLX5_IB_LATENCY_CLASS_MEDIUM,
+ MLX5_IB_LATENCY_CLASS_HIGH,
+ MLX5_IB_LATENCY_CLASS_FAST_PATH
+};
+
+enum mlx5_ib_mad_ifc_flags {
+ MLX5_MAD_IFC_IGNORE_MKEY = 1,
+ MLX5_MAD_IFC_IGNORE_BKEY = 2,
+ MLX5_MAD_IFC_NET_VIEW = 4,
+};
+
+struct mlx5_ib_ucontext {
+ struct ib_ucontext ibucontext;
+ struct list_head db_page_list;
+
+ /* protect doorbell record alloc/free
+ */
+ struct mutex db_page_mutex;
+ struct mlx5_uuar_info uuari;
+};
+
+static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct mlx5_ib_ucontext, ibucontext);
+}
+
+struct mlx5_ib_pd {
+ struct ib_pd ibpd;
+ u32 pdn;
+ u32 pa_lkey;
+};
+
+/* Use macros here so that don't have to duplicate
+ * enum ib_send_flags and enum ib_qp_type for low-level driver
+ */
+
+#define MLX5_IB_SEND_UMR_UNREG IB_SEND_RESERVED_START
+#define MLX5_IB_QPT_REG_UMR IB_QPT_RESERVED1
+#define MLX5_IB_WR_UMR IB_WR_RESERVED1
+
+struct wr_list {
+ u16 opcode;
+ u16 next;
+};
+
+struct mlx5_ib_wq {
+ u64 *wrid;
+ u32 *wr_data;
+ struct wr_list *w_list;
+ unsigned *wqe_head;
+ u16 unsig_count;
+
+ /* serialize post to the work queue
+ */
+ spinlock_t lock;
+ int wqe_cnt;
+ int max_post;
+ int max_gs;
+ int offset;
+ int wqe_shift;
+ unsigned head;
+ unsigned tail;
+ u16 cur_post;
+ u16 last_poll;
+ void *qend;
+};
+
+enum {
+ MLX5_QP_USER,
+ MLX5_QP_KERNEL,
+ MLX5_QP_EMPTY
+};
+
+struct mlx5_ib_qp {
+ struct ib_qp ibqp;
+ struct mlx5_core_qp mqp;
+ struct mlx5_buf buf;
+
+ struct mlx5_db db;
+ struct mlx5_ib_wq rq;
+
+ u32 doorbell_qpn;
+ u8 sq_signal_bits;
+ u8 fm_cache;
+ int sq_max_wqes_per_wr;
+ int sq_spare_wqes;
+ struct mlx5_ib_wq sq;
+
+ struct ib_umem *umem;
+ int buf_size;
+
+ /* serialize qp state modifications
+ */
+ struct mutex mutex;
+ u16 xrcdn;
+ u32 flags;
+ u8 port;
+ u8 alt_port;
+ u8 atomic_rd_en;
+ u8 resp_depth;
+ u8 state;
+ int mlx_type;
+ int wq_sig;
+ int scat_cqe;
+ int max_inline_data;
+ struct mlx5_bf *bf;
+ int has_rq;
+
+ /* only for user space QPs. For kernel
+ * we have it from the bf object
+ */
+ int uuarn;
+
+ int create_type;
+ u32 pa_lkey;
+};
+
+struct mlx5_ib_cq_buf {
+ struct mlx5_buf buf;
+ struct ib_umem *umem;
+ int cqe_size;
+};
+
+enum mlx5_ib_qp_flags {
+ MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 0,
+ MLX5_IB_QP_SIGNATURE_HANDLING = 1 << 1,
+};
+
+struct mlx5_shared_mr_info {
+ int mr_id;
+ struct ib_umem *umem;
+};
+
+struct mlx5_ib_cq {
+ struct ib_cq ibcq;
+ struct mlx5_core_cq mcq;
+ struct mlx5_ib_cq_buf buf;
+ struct mlx5_db db;
+
+ /* serialize access to the CQ
+ */
+ spinlock_t lock;
+
+ /* protect resize cq
+ */
+ struct mutex resize_mutex;
+ struct mlx5_ib_cq_resize *resize_buf;
+ struct ib_umem *resize_umem;
+ int cqe_size;
+};
+
+struct mlx5_ib_srq {
+ struct ib_srq ibsrq;
+ struct mlx5_core_srq msrq;
+ struct mlx5_buf buf;
+ struct mlx5_db db;
+ u64 *wrid;
+ /* protect SRQ hanlding
+ */
+ spinlock_t lock;
+ int head;
+ int tail;
+ u16 wqe_ctr;
+ struct ib_umem *umem;
+ /* serialize arming a SRQ
+ */
+ struct mutex mutex;
+ int wq_sig;
+};
+
+struct mlx5_ib_xrcd {
+ struct ib_xrcd ibxrcd;
+ u32 xrcdn;
+};
+
+struct mlx5_ib_mr {
+ struct ib_mr ibmr;
+ struct mlx5_core_mr mmr;
+ struct ib_umem *umem;
+ struct mlx5_shared_mr_info *smr_info;
+ struct list_head list;
+ int order;
+ int umred;
+ __be64 *pas;
+ dma_addr_t dma;
+ int npages;
+ struct completion done;
+ enum ib_wc_status status;
+};
+
+struct mlx5_ib_fast_reg_page_list {
+ struct ib_fast_reg_page_list ibfrpl;
+ __be64 *mapped_page_list;
+ dma_addr_t map;
+};
+
+struct umr_common {
+ struct ib_pd *pd;
+ struct ib_cq *cq;
+ struct ib_qp *qp;
+ struct ib_mr *mr;
+ /* control access to UMR QP
+ */
+ struct semaphore sem;
+};
+
+enum {
+ MLX5_FMR_INVALID,
+ MLX5_FMR_VALID,
+ MLX5_FMR_BUSY,
+};
+
+struct mlx5_ib_fmr {
+ struct ib_fmr ibfmr;
+ struct mlx5_core_mr mr;
+ int access_flags;
+ int state;
+ /* protect fmr state
+ */
+ spinlock_t lock;
+ u64 wrid;
+ struct ib_send_wr wr[2];
+ u8 page_shift;
+ struct ib_fast_reg_page_list page_list;
+};
+
+struct mlx5_cache_ent {
+ struct list_head head;
+ /* sync access to the cahce entry
+ */
+ spinlock_t lock;
+
+
+ struct dentry *dir;
+ char name[4];
+ u32 order;
+ u32 size;
+ u32 cur;
+ u32 miss;
+ u32 limit;
+
+ struct dentry *fsize;
+ struct dentry *fcur;
+ struct dentry *fmiss;
+ struct dentry *flimit;
+
+ struct mlx5_ib_dev *dev;
+ struct work_struct work;
+ struct delayed_work dwork;
+};
+
+struct mlx5_mr_cache {
+ struct workqueue_struct *wq;
+ struct mlx5_cache_ent ent[MAX_MR_CACHE_ENTRIES];
+ int stopped;
+ struct dentry *root;
+ unsigned long last_add;
+};
+
+struct mlx5_ib_resources {
+ struct ib_cq *c0;
+ struct ib_xrcd *x0;
+ struct ib_xrcd *x1;
+ struct ib_pd *p0;
+ struct ib_srq *s0;
+};
+
+struct mlx5_ib_dev {
+ struct ib_device ib_dev;
+ struct mlx5_core_dev mdev;
+ MLX5_DECLARE_DOORBELL_LOCK(uar_lock);
+ struct list_head eqs_list;
+ int num_ports;
+ int num_comp_vectors;
+ /* serialize update of capability mask
+ */
+ struct mutex cap_mask_mutex;
+ bool ib_active;
+ struct umr_common umrc;
+ /* sync used page count stats
+ */
+ spinlock_t mr_lock;
+ struct mlx5_ib_resources devr;
+ struct mlx5_mr_cache cache;
+};
+
+static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
+{
+ return container_of(mcq, struct mlx5_ib_cq, mcq);
+}
+
+static inline struct mlx5_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd)
+{
+ return container_of(ibxrcd, struct mlx5_ib_xrcd, ibxrcd);
+}
+
+static inline struct mlx5_ib_dev *to_mdev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct mlx5_ib_dev, ib_dev);
+}
+
+static inline struct mlx5_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
+{
+ return container_of(ibfmr, struct mlx5_ib_fmr, ibfmr);
+}
+
+static inline struct mlx5_ib_cq *to_mcq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct mlx5_ib_cq, ibcq);
+}
+
+static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp)
+{
+ return container_of(mqp, struct mlx5_ib_qp, mqp);
+}
+
+static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct mlx5_ib_pd, ibpd);
+}
+
+static inline struct mlx5_ib_srq *to_msrq(struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct mlx5_ib_srq, ibsrq);
+}
+
+static inline struct mlx5_ib_qp *to_mqp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct mlx5_ib_qp, ibqp);
+}
+
+static inline struct mlx5_ib_srq *to_mibsrq(struct mlx5_core_srq *msrq)
+{
+ return container_of(msrq, struct mlx5_ib_srq, msrq);
+}
+
+static inline struct mlx5_ib_mr *to_mmr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct mlx5_ib_mr, ibmr);
+}
+
+static inline struct mlx5_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl)
+{
+ return container_of(ibfrpl, struct mlx5_ib_fast_reg_page_list, ibfrpl);
+}
+
+struct mlx5_ib_ah {
+ struct ib_ah ibah;
+ struct mlx5_av av;
+};
+
+static inline struct mlx5_ib_ah *to_mah(struct ib_ah *ibah)
+{
+ return container_of(ibah, struct mlx5_ib_ah, ibah);
+}
+
+static inline struct mlx5_ib_dev *mlx5_core2ibdev(struct mlx5_core_dev *dev)
+{
+ return container_of(dev, struct mlx5_ib_dev, mdev);
+}
+
+static inline struct mlx5_ib_dev *mlx5_pci2ibdev(struct pci_dev *pdev)
+{
+ return mlx5_core2ibdev(pci2mlx5_core_dev(pdev));
+}
+
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
+ struct mlx5_db *db);
+void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db);
+void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq);
+void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq);
+void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index);
+int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+ void *in_mad, void *response_mad);
+struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr,
+ struct mlx5_ib_ah *ah);
+struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr);
+int mlx5_ib_destroy_ah(struct ib_ah *ah);
+struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata);
+int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
+int mlx5_ib_destroy_srq(struct ib_srq *srq);
+int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr);
+struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr);
+int mlx5_ib_destroy_qp(struct ib_qp *qp);
+int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr);
+int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr);
+void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n);
+struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries,
+ int vector, struct ib_ucontext *context,
+ struct ib_udata *udata);
+int mlx5_ib_destroy_cq(struct ib_cq *cq);
+int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);
+int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
+struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc);
+struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt_addr, int access_flags,
+ struct ib_udata *udata);
+int mlx5_ib_dereg_mr(struct ib_mr *ibmr);
+struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
+ int max_page_list_len);
+struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
+ int page_list_len);
+void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list);
+struct ib_fmr *mlx5_ib_fmr_alloc(struct ib_pd *pd, int acc,
+ struct ib_fmr_attr *fmr_attr);
+int mlx5_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+ int npages, u64 iova);
+int mlx5_ib_unmap_fmr(struct list_head *fmr_list);
+int mlx5_ib_fmr_dealloc(struct ib_fmr *ibfmr);
+int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+ struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad);
+struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd);
+int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn);
+int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset);
+int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port);
+int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
+int mlx5_ib_init_fmr(struct mlx5_ib_dev *dev);
+void mlx5_ib_cleanup_fmr(struct mlx5_ib_dev *dev);
+void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
+ int *ncont, int *order);
+void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
+ int page_shift, __be64 *pas, int umr);
+void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num);
+int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq);
+int mlx5_mr_cache_init(struct mlx5_ib_dev *dev);
+int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);
+int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift);
+void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context);
+
+static inline void init_query_mad(struct ib_smp *mad)
+{
+ mad->base_version = 1;
+ mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->class_version = 1;
+ mad->method = IB_MGMT_METHOD_GET;
+}
+
+static inline u8 convert_access(int acc)
+{
+ return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) |
+ (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) |
+ (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) |
+ MLX5_PERM_LOCAL_READ;
+}
+
+#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
new file mode 100644
index 000000000000..bd41df95b6f0
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <linux/kref.h>
+#include <linux/random.h>
+#include <linux/debugfs.h>
+#include <linux/export.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+
+enum {
+ DEF_CACHE_SIZE = 10,
+};
+
+static __be64 *mr_align(__be64 *ptr, int align)
+{
+ unsigned long mask = align - 1;
+
+ return (__be64 *)(((unsigned long)ptr + mask) & ~mask);
+}
+
+static int order2idx(struct mlx5_ib_dev *dev, int order)
+{
+ struct mlx5_mr_cache *cache = &dev->cache;
+
+ if (order < cache->ent[0].order)
+ return 0;
+ else
+ return order - cache->ent[0].order;
+}
+
+static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
+{
+ struct device *ddev = dev->ib_dev.dma_device;
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent = &cache->ent[c];
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_ib_mr *mr;
+ int npages = 1 << ent->order;
+ int size = sizeof(u64) * npages;
+ int err = 0;
+ int i;
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++) {
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ err = -ENOMEM;
+ goto out;
+ }
+ mr->order = ent->order;
+ mr->umred = 1;
+ mr->pas = kmalloc(size + 0x3f, GFP_KERNEL);
+ if (!mr->pas) {
+ kfree(mr);
+ err = -ENOMEM;
+ goto out;
+ }
+ mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ddev, mr->dma)) {
+ kfree(mr->pas);
+ kfree(mr);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ in->seg.status = 1 << 6;
+ in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2);
+ in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN;
+ in->seg.log2_page_size = 12;
+
+ err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in,
+ sizeof(*in));
+ if (err) {
+ mlx5_ib_warn(dev, "create mkey failed %d\n", err);
+ dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+ kfree(mr->pas);
+ kfree(mr);
+ goto out;
+ }
+ cache->last_add = jiffies;
+
+ spin_lock(&ent->lock);
+ list_add_tail(&mr->list, &ent->head);
+ ent->cur++;
+ ent->size++;
+ spin_unlock(&ent->lock);
+ }
+
+out:
+ kfree(in);
+ return err;
+}
+
+static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
+{
+ struct device *ddev = dev->ib_dev.dma_device;
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent = &cache->ent[c];
+ struct mlx5_ib_mr *mr;
+ int size;
+ int err;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ spin_lock(&ent->lock);
+ if (list_empty(&ent->head)) {
+ spin_unlock(&ent->lock);
+ return;
+ }
+ mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
+ list_del(&mr->list);
+ ent->cur--;
+ ent->size--;
+ spin_unlock(&ent->lock);
+ err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+ if (err) {
+ mlx5_ib_warn(dev, "failed destroy mkey\n");
+ } else {
+ size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
+ dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+ kfree(mr->pas);
+ kfree(mr);
+ }
+ }
+}
+
+static ssize_t size_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_cache_ent *ent = filp->private_data;
+ struct mlx5_ib_dev *dev = ent->dev;
+ char lbuf[20];
+ u32 var;
+ int err;
+ int c;
+
+ if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+ return -EFAULT;
+
+ c = order2idx(dev, ent->order);
+ lbuf[sizeof(lbuf) - 1] = 0;
+
+ if (sscanf(lbuf, "%u", &var) != 1)
+ return -EINVAL;
+
+ if (var < ent->limit)
+ return -EINVAL;
+
+ if (var > ent->size) {
+ err = add_keys(dev, c, var - ent->size);
+ if (err)
+ return err;
+ } else if (var < ent->size) {
+ remove_keys(dev, c, ent->size - var);
+ }
+
+ return count;
+}
+
+static ssize_t size_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_cache_ent *ent = filp->private_data;
+ char lbuf[20];
+ int err;
+
+ if (*pos)
+ return 0;
+
+ err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->size);
+ if (err < 0)
+ return err;
+
+ if (copy_to_user(buf, lbuf, err))
+ return -EFAULT;
+
+ *pos += err;
+
+ return err;
+}
+
+static const struct file_operations size_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = size_write,
+ .read = size_read,
+};
+
+static ssize_t limit_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_cache_ent *ent = filp->private_data;
+ struct mlx5_ib_dev *dev = ent->dev;
+ char lbuf[20];
+ u32 var;
+ int err;
+ int c;
+
+ if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+ return -EFAULT;
+
+ c = order2idx(dev, ent->order);
+ lbuf[sizeof(lbuf) - 1] = 0;
+
+ if (sscanf(lbuf, "%u", &var) != 1)
+ return -EINVAL;
+
+ if (var > ent->size)
+ return -EINVAL;
+
+ ent->limit = var;
+
+ if (ent->cur < ent->limit) {
+ err = add_keys(dev, c, 2 * ent->limit - ent->cur);
+ if (err)
+ return err;
+ }
+
+ return count;
+}
+
+static ssize_t limit_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_cache_ent *ent = filp->private_data;
+ char lbuf[20];
+ int err;
+
+ if (*pos)
+ return 0;
+
+ err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit);
+ if (err < 0)
+ return err;
+
+ if (copy_to_user(buf, lbuf, err))
+ return -EFAULT;
+
+ *pos += err;
+
+ return err;
+}
+
+static const struct file_operations limit_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = limit_write,
+ .read = limit_read,
+};
+
+static int someone_adding(struct mlx5_mr_cache *cache)
+{
+ int i;
+
+ for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+ if (cache->ent[i].cur < cache->ent[i].limit)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void __cache_work_func(struct mlx5_cache_ent *ent)
+{
+ struct mlx5_ib_dev *dev = ent->dev;
+ struct mlx5_mr_cache *cache = &dev->cache;
+ int i = order2idx(dev, ent->order);
+
+ if (cache->stopped)
+ return;
+
+ ent = &dev->cache.ent[i];
+ if (ent->cur < 2 * ent->limit) {
+ add_keys(dev, i, 1);
+ if (ent->cur < 2 * ent->limit)
+ queue_work(cache->wq, &ent->work);
+ } else if (ent->cur > 2 * ent->limit) {
+ if (!someone_adding(cache) &&
+ time_after(jiffies, cache->last_add + 60 * HZ)) {
+ remove_keys(dev, i, 1);
+ if (ent->cur > ent->limit)
+ queue_work(cache->wq, &ent->work);
+ } else {
+ queue_delayed_work(cache->wq, &ent->dwork, 60 * HZ);
+ }
+ }
+}
+
+static void delayed_cache_work_func(struct work_struct *work)
+{
+ struct mlx5_cache_ent *ent;
+
+ ent = container_of(work, struct mlx5_cache_ent, dwork.work);
+ __cache_work_func(ent);
+}
+
+static void cache_work_func(struct work_struct *work)
+{
+ struct mlx5_cache_ent *ent;
+
+ ent = container_of(work, struct mlx5_cache_ent, work);
+ __cache_work_func(ent);
+}
+
+static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order)
+{
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_ib_mr *mr = NULL;
+ struct mlx5_cache_ent *ent;
+ int c;
+ int i;
+
+ c = order2idx(dev, order);
+ if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
+ mlx5_ib_warn(dev, "order %d, cache index %d\n", order, c);
+ return NULL;
+ }
+
+ for (i = c; i < MAX_MR_CACHE_ENTRIES; i++) {
+ ent = &cache->ent[i];
+
+ mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i);
+
+ spin_lock(&ent->lock);
+ if (!list_empty(&ent->head)) {
+ mr = list_first_entry(&ent->head, struct mlx5_ib_mr,
+ list);
+ list_del(&mr->list);
+ ent->cur--;
+ spin_unlock(&ent->lock);
+ if (ent->cur < ent->limit)
+ queue_work(cache->wq, &ent->work);
+ break;
+ }
+ spin_unlock(&ent->lock);
+
+ queue_work(cache->wq, &ent->work);
+
+ if (mr)
+ break;
+ }
+
+ if (!mr)
+ cache->ent[c].miss++;
+
+ return mr;
+}
+
+static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
+{
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent;
+ int shrink = 0;
+ int c;
+
+ c = order2idx(dev, mr->order);
+ if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
+ mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c);
+ return;
+ }
+ ent = &cache->ent[c];
+ spin_lock(&ent->lock);
+ list_add_tail(&mr->list, &ent->head);
+ ent->cur++;
+ if (ent->cur > 2 * ent->limit)
+ shrink = 1;
+ spin_unlock(&ent->lock);
+
+ if (shrink)
+ queue_work(cache->wq, &ent->work);
+}
+
+static void clean_keys(struct mlx5_ib_dev *dev, int c)
+{
+ struct device *ddev = dev->ib_dev.dma_device;
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent = &cache->ent[c];
+ struct mlx5_ib_mr *mr;
+ int size;
+ int err;
+
+ while (1) {
+ spin_lock(&ent->lock);
+ if (list_empty(&ent->head)) {
+ spin_unlock(&ent->lock);
+ return;
+ }
+ mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
+ list_del(&mr->list);
+ ent->cur--;
+ ent->size--;
+ spin_unlock(&ent->lock);
+ err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+ if (err) {
+ mlx5_ib_warn(dev, "failed destroy mkey\n");
+ } else {
+ size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
+ dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+ kfree(mr->pas);
+ kfree(mr);
+ }
+ }
+}
+
+static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent;
+ int i;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ cache->root = debugfs_create_dir("mr_cache", dev->mdev.priv.dbg_root);
+ if (!cache->root)
+ return -ENOMEM;
+
+ for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+ ent = &cache->ent[i];
+ sprintf(ent->name, "%d", ent->order);
+ ent->dir = debugfs_create_dir(ent->name, cache->root);
+ if (!ent->dir)
+ return -ENOMEM;
+
+ ent->fsize = debugfs_create_file("size", 0600, ent->dir, ent,
+ &size_fops);
+ if (!ent->fsize)
+ return -ENOMEM;
+
+ ent->flimit = debugfs_create_file("limit", 0600, ent->dir, ent,
+ &limit_fops);
+ if (!ent->flimit)
+ return -ENOMEM;
+
+ ent->fcur = debugfs_create_u32("cur", 0400, ent->dir,
+ &ent->cur);
+ if (!ent->fcur)
+ return -ENOMEM;
+
+ ent->fmiss = debugfs_create_u32("miss", 0600, ent->dir,
+ &ent->miss);
+ if (!ent->fmiss)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(dev->cache.root);
+}
+
+int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_mr_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent;
+ int limit;
+ int size;
+ int err;
+ int i;
+
+ cache->wq = create_singlethread_workqueue("mkey_cache");
+ if (!cache->wq) {
+ mlx5_ib_warn(dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+ INIT_LIST_HEAD(&cache->ent[i].head);
+ spin_lock_init(&cache->ent[i].lock);
+
+ ent = &cache->ent[i];
+ INIT_LIST_HEAD(&ent->head);
+ spin_lock_init(&ent->lock);
+ ent->order = i + 2;
+ ent->dev = dev;
+
+ if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) {
+ size = dev->mdev.profile->mr_cache[i].size;
+ limit = dev->mdev.profile->mr_cache[i].limit;
+ } else {
+ size = DEF_CACHE_SIZE;
+ limit = 0;
+ }
+ INIT_WORK(&ent->work, cache_work_func);
+ INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
+ ent->limit = limit;
+ queue_work(cache->wq, &ent->work);
+ }
+
+ err = mlx5_mr_cache_debugfs_init(dev);
+ if (err)
+ mlx5_ib_warn(dev, "cache debugfs failure\n");
+
+ return 0;
+}
+
+int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
+{
+ int i;
+
+ dev->cache.stopped = 1;
+ destroy_workqueue(dev->cache.wq);
+
+ mlx5_mr_cache_debugfs_cleanup(dev);
+
+ for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++)
+ clean_keys(dev, i);
+
+ return 0;
+}
+
+struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_core_dev *mdev = &dev->mdev;
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_mkey_seg *seg;
+ struct mlx5_ib_mr *mr;
+ int err;
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ seg = &in->seg;
+ seg->flags = convert_access(acc) | MLX5_ACCESS_MODE_PA;
+ seg->flags_pd = cpu_to_be32(to_mpd(pd)->pdn | MLX5_MKEY_LEN64);
+ seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ seg->start_addr = 0;
+
+ err = mlx5_core_create_mkey(mdev, &mr->mmr, in, sizeof(*in));
+ if (err)
+ goto err_in;
+
+ kfree(in);
+ mr->ibmr.lkey = mr->mmr.key;
+ mr->ibmr.rkey = mr->mmr.key;
+ mr->umem = NULL;
+
+ return &mr->ibmr;
+
+err_in:
+ kfree(in);
+
+err_free:
+ kfree(mr);
+
+ return ERR_PTR(err);
+}
+
+static int get_octo_len(u64 addr, u64 len, int page_size)
+{
+ u64 offset;
+ int npages;
+
+ offset = addr & (page_size - 1);
+ npages = ALIGN(len + offset, page_size) >> ilog2(page_size);
+ return (npages + 1) / 2;
+}
+
+static int use_umr(int order)
+{
+ return order <= 17;
+}
+
+static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
+ struct ib_sge *sg, u64 dma, int n, u32 key,
+ int page_shift, u64 virt_addr, u64 len,
+ int access_flags)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct ib_mr *mr = dev->umrc.mr;
+
+ sg->addr = dma;
+ sg->length = ALIGN(sizeof(u64) * n, 64);
+ sg->lkey = mr->lkey;
+
+ wr->next = NULL;
+ wr->send_flags = 0;
+ wr->sg_list = sg;
+ if (n)
+ wr->num_sge = 1;
+ else
+ wr->num_sge = 0;
+
+ wr->opcode = MLX5_IB_WR_UMR;
+ wr->wr.fast_reg.page_list_len = n;
+ wr->wr.fast_reg.page_shift = page_shift;
+ wr->wr.fast_reg.rkey = key;
+ wr->wr.fast_reg.iova_start = virt_addr;
+ wr->wr.fast_reg.length = len;
+ wr->wr.fast_reg.access_flags = access_flags;
+ wr->wr.fast_reg.page_list = (struct ib_fast_reg_page_list *)pd;
+}
+
+static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev,
+ struct ib_send_wr *wr, u32 key)
+{
+ wr->send_flags = MLX5_IB_SEND_UMR_UNREG;
+ wr->opcode = MLX5_IB_WR_UMR;
+ wr->wr.fast_reg.rkey = key;
+}
+
+void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context)
+{
+ struct mlx5_ib_mr *mr;
+ struct ib_wc wc;
+ int err;
+
+ while (1) {
+ err = ib_poll_cq(cq, 1, &wc);
+ if (err < 0) {
+ pr_warn("poll cq error %d\n", err);
+ return;
+ }
+ if (err == 0)
+ break;
+
+ mr = (struct mlx5_ib_mr *)(unsigned long)wc.wr_id;
+ mr->status = wc.status;
+ complete(&mr->done);
+ }
+ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+}
+
+static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
+ u64 virt_addr, u64 len, int npages,
+ int page_shift, int order, int access_flags)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct umr_common *umrc = &dev->umrc;
+ struct ib_send_wr wr, *bad;
+ struct mlx5_ib_mr *mr;
+ struct ib_sge sg;
+ int err;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ mr = alloc_cached_mr(dev, order);
+ if (mr)
+ break;
+
+ err = add_keys(dev, order2idx(dev, order), 1);
+ if (err) {
+ mlx5_ib_warn(dev, "add_keys failed\n");
+ break;
+ }
+ }
+
+ if (!mr)
+ return ERR_PTR(-EAGAIN);
+
+ mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1);
+
+ memset(&wr, 0, sizeof(wr));
+ wr.wr_id = (u64)(unsigned long)mr;
+ prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags);
+
+ /* We serialize polls so one process does not kidnap another's
+ * completion. This is not a problem since wr is completed in
+ * around 1 usec
+ */
+ down(&umrc->sem);
+ init_completion(&mr->done);
+ err = ib_post_send(umrc->qp, &wr, &bad);
+ if (err) {
+ mlx5_ib_warn(dev, "post send failed, err %d\n", err);
+ up(&umrc->sem);
+ goto error;
+ }
+ wait_for_completion(&mr->done);
+ up(&umrc->sem);
+
+ if (mr->status != IB_WC_SUCCESS) {
+ mlx5_ib_warn(dev, "reg umr failed\n");
+ err = -EFAULT;
+ goto error;
+ }
+
+ return mr;
+
+error:
+ free_cached_mr(dev, mr);
+ return ERR_PTR(err);
+}
+
+static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
+ u64 length, struct ib_umem *umem,
+ int npages, int page_shift,
+ int access_flags)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_ib_mr *mr;
+ int inlen;
+ int err;
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ inlen = sizeof(*in) + sizeof(*in->pas) * ((npages + 1) / 2) * 2;
+ in = mlx5_vzalloc(inlen);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_1;
+ }
+ mlx5_ib_populate_pas(dev, umem, page_shift, in->pas, 0);
+
+ in->seg.flags = convert_access(access_flags) |
+ MLX5_ACCESS_MODE_MTT;
+ in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+ in->seg.start_addr = cpu_to_be64(virt_addr);
+ in->seg.len = cpu_to_be64(length);
+ in->seg.bsfs_octo_size = 0;
+ in->seg.xlt_oct_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift));
+ in->seg.log2_page_size = page_shift;
+ in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift));
+ err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen);
+ if (err) {
+ mlx5_ib_warn(dev, "create mkey failed\n");
+ goto err_2;
+ }
+ mr->umem = umem;
+ mlx5_vfree(in);
+
+ mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmr.key);
+
+ return mr;
+
+err_2:
+ mlx5_vfree(in);
+
+err_1:
+ kfree(mr);
+
+ return ERR_PTR(err);
+}
+
+struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt_addr, int access_flags,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_ib_mr *mr = NULL;
+ struct ib_umem *umem;
+ int page_shift;
+ int npages;
+ int ncont;
+ int order;
+ int err;
+
+ mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx\n",
+ start, virt_addr, length);
+ umem = ib_umem_get(pd->uobject->context, start, length, access_flags,
+ 0);
+ if (IS_ERR(umem)) {
+ mlx5_ib_dbg(dev, "umem get failed\n");
+ return (void *)umem;
+ }
+
+ mlx5_ib_cont_pages(umem, start, &npages, &page_shift, &ncont, &order);
+ if (!npages) {
+ mlx5_ib_warn(dev, "avoid zero region\n");
+ err = -EINVAL;
+ goto error;
+ }
+
+ mlx5_ib_dbg(dev, "npages %d, ncont %d, order %d, page_shift %d\n",
+ npages, ncont, order, page_shift);
+
+ if (use_umr(order)) {
+ mr = reg_umr(pd, umem, virt_addr, length, ncont, page_shift,
+ order, access_flags);
+ if (PTR_ERR(mr) == -EAGAIN) {
+ mlx5_ib_dbg(dev, "cache empty for order %d", order);
+ mr = NULL;
+ }
+ }
+
+ if (!mr)
+ mr = reg_create(pd, virt_addr, length, umem, ncont, page_shift,
+ access_flags);
+
+ if (IS_ERR(mr)) {
+ err = PTR_ERR(mr);
+ goto error;
+ }
+
+ mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmr.key);
+
+ mr->umem = umem;
+ mr->npages = npages;
+ spin_lock(&dev->mr_lock);
+ dev->mdev.priv.reg_pages += npages;
+ spin_unlock(&dev->mr_lock);
+ mr->ibmr.lkey = mr->mmr.key;
+ mr->ibmr.rkey = mr->mmr.key;
+
+ return &mr->ibmr;
+
+error:
+ ib_umem_release(umem);
+ return ERR_PTR(err);
+}
+
+static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
+{
+ struct umr_common *umrc = &dev->umrc;
+ struct ib_send_wr wr, *bad;
+ int err;
+
+ memset(&wr, 0, sizeof(wr));
+ wr.wr_id = (u64)(unsigned long)mr;
+ prep_umr_unreg_wqe(dev, &wr, mr->mmr.key);
+
+ down(&umrc->sem);
+ init_completion(&mr->done);
+ err = ib_post_send(umrc->qp, &wr, &bad);
+ if (err) {
+ up(&umrc->sem);
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ goto error;
+ }
+ wait_for_completion(&mr->done);
+ up(&umrc->sem);
+ if (mr->status != IB_WC_SUCCESS) {
+ mlx5_ib_warn(dev, "unreg umr failed\n");
+ err = -EFAULT;
+ goto error;
+ }
+ return 0;
+
+error:
+ return err;
+}
+
+int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ struct ib_umem *umem = mr->umem;
+ int npages = mr->npages;
+ int umred = mr->umred;
+ int err;
+
+ if (!umred) {
+ err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+ if (err) {
+ mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n",
+ mr->mmr.key, err);
+ return err;
+ }
+ } else {
+ err = unreg_umr(dev, mr);
+ if (err) {
+ mlx5_ib_warn(dev, "failed unregister\n");
+ return err;
+ }
+ free_cached_mr(dev, mr);
+ }
+
+ if (umem) {
+ ib_umem_release(umem);
+ spin_lock(&dev->mr_lock);
+ dev->mdev.priv.reg_pages -= npages;
+ spin_unlock(&dev->mr_lock);
+ }
+
+ if (!umred)
+ kfree(mr);
+
+ return 0;
+}
+
+struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
+ int max_page_list_len)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_ib_mr *mr;
+ int err;
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ in->seg.status = 1 << 6; /* free */
+ in->seg.xlt_oct_size = cpu_to_be32((max_page_list_len + 1) / 2);
+ in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
+ in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+ /*
+ * TBD not needed - issue 197292 */
+ in->seg.log2_page_size = PAGE_SHIFT;
+
+ err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in));
+ kfree(in);
+ if (err)
+ goto err_free;
+
+ mr->ibmr.lkey = mr->mmr.key;
+ mr->ibmr.rkey = mr->mmr.key;
+ mr->umem = NULL;
+
+ return &mr->ibmr;
+
+err_free:
+ kfree(mr);
+ return ERR_PTR(err);
+}
+
+struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
+ int page_list_len)
+{
+ struct mlx5_ib_fast_reg_page_list *mfrpl;
+ int size = page_list_len * sizeof(u64);
+
+ mfrpl = kmalloc(sizeof(*mfrpl), GFP_KERNEL);
+ if (!mfrpl)
+ return ERR_PTR(-ENOMEM);
+
+ mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL);
+ if (!mfrpl->ibfrpl.page_list)
+ goto err_free;
+
+ mfrpl->mapped_page_list = dma_alloc_coherent(ibdev->dma_device,
+ size, &mfrpl->map,
+ GFP_KERNEL);
+ if (!mfrpl->mapped_page_list)
+ goto err_free;
+
+ WARN_ON(mfrpl->map & 0x3f);
+
+ return &mfrpl->ibfrpl;
+
+err_free:
+ kfree(mfrpl->ibfrpl.page_list);
+ kfree(mfrpl);
+ return ERR_PTR(-ENOMEM);
+}
+
+void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
+{
+ struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list);
+ struct mlx5_ib_dev *dev = to_mdev(page_list->device);
+ int size = page_list->max_page_list_len * sizeof(u64);
+
+ dma_free_coherent(&dev->mdev.pdev->dev, size, mfrpl->mapped_page_list,
+ mfrpl->map);
+ kfree(mfrpl->ibfrpl.page_list);
+ kfree(mfrpl);
+}
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
new file mode 100644
index 000000000000..16ac54c9819f
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -0,0 +1,2524 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+#include "user.h"
+
+/* not supported currently */
+static int wq_signature;
+
+enum {
+ MLX5_IB_ACK_REQ_FREQ = 8,
+};
+
+enum {
+ MLX5_IB_DEFAULT_SCHED_QUEUE = 0x83,
+ MLX5_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f,
+ MLX5_IB_LINK_TYPE_IB = 0,
+ MLX5_IB_LINK_TYPE_ETH = 1
+};
+
+enum {
+ MLX5_IB_SQ_STRIDE = 6,
+ MLX5_IB_CACHE_LINE_SIZE = 64,
+};
+
+static const u32 mlx5_ib_opcode[] = {
+ [IB_WR_SEND] = MLX5_OPCODE_SEND,
+ [IB_WR_SEND_WITH_IMM] = MLX5_OPCODE_SEND_IMM,
+ [IB_WR_RDMA_WRITE] = MLX5_OPCODE_RDMA_WRITE,
+ [IB_WR_RDMA_WRITE_WITH_IMM] = MLX5_OPCODE_RDMA_WRITE_IMM,
+ [IB_WR_RDMA_READ] = MLX5_OPCODE_RDMA_READ,
+ [IB_WR_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_CS,
+ [IB_WR_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_FA,
+ [IB_WR_SEND_WITH_INV] = MLX5_OPCODE_SEND_INVAL,
+ [IB_WR_LOCAL_INV] = MLX5_OPCODE_UMR,
+ [IB_WR_FAST_REG_MR] = MLX5_OPCODE_UMR,
+ [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_MASKED_CS,
+ [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_MASKED_FA,
+ [MLX5_IB_WR_UMR] = MLX5_OPCODE_UMR,
+};
+
+struct umr_wr {
+ u64 virt_addr;
+ struct ib_pd *pd;
+ unsigned int page_shift;
+ unsigned int npages;
+ u32 length;
+ int access_flags;
+ u32 mkey;
+};
+
+static int is_qp0(enum ib_qp_type qp_type)
+{
+ return qp_type == IB_QPT_SMI;
+}
+
+static int is_qp1(enum ib_qp_type qp_type)
+{
+ return qp_type == IB_QPT_GSI;
+}
+
+static int is_sqp(enum ib_qp_type qp_type)
+{
+ return is_qp0(qp_type) || is_qp1(qp_type);
+}
+
+static void *get_wqe(struct mlx5_ib_qp *qp, int offset)
+{
+ return mlx5_buf_offset(&qp->buf, offset);
+}
+
+static void *get_recv_wqe(struct mlx5_ib_qp *qp, int n)
+{
+ return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift));
+}
+
+void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n)
+{
+ return get_wqe(qp, qp->sq.offset + (n << MLX5_IB_SQ_STRIDE));
+}
+
+static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
+{
+ struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
+ struct ib_event event;
+
+ if (type == MLX5_EVENT_TYPE_PATH_MIG)
+ to_mibqp(qp)->port = to_mibqp(qp)->alt_port;
+
+ if (ibqp->event_handler) {
+ event.device = ibqp->device;
+ event.element.qp = ibqp;
+ switch (type) {
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ event.event = IB_EVENT_PATH_MIG;
+ break;
+ case MLX5_EVENT_TYPE_COMM_EST:
+ event.event = IB_EVENT_COMM_EST;
+ break;
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ event.event = IB_EVENT_SQ_DRAINED;
+ break;
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_QP_FATAL;
+ break;
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ event.event = IB_EVENT_PATH_MIG_ERR;
+ break;
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ event.event = IB_EVENT_QP_REQ_ERR;
+ break;
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ event.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ default:
+ pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn);
+ return;
+ }
+
+ ibqp->event_handler(&event, ibqp->qp_context);
+ }
+}
+
+static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
+ int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd)
+{
+ int wqe_size;
+ int wq_size;
+
+ /* Sanity check RQ size before proceeding */
+ if (cap->max_recv_wr > dev->mdev.caps.max_wqes)
+ return -EINVAL;
+
+ if (!has_rq) {
+ qp->rq.max_gs = 0;
+ qp->rq.wqe_cnt = 0;
+ qp->rq.wqe_shift = 0;
+ } else {
+ if (ucmd) {
+ qp->rq.wqe_cnt = ucmd->rq_wqe_count;
+ qp->rq.wqe_shift = ucmd->rq_wqe_shift;
+ qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
+ qp->rq.max_post = qp->rq.wqe_cnt;
+ } else {
+ wqe_size = qp->wq_sig ? sizeof(struct mlx5_wqe_signature_seg) : 0;
+ wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg);
+ wqe_size = roundup_pow_of_two(wqe_size);
+ wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size;
+ wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB);
+ qp->rq.wqe_cnt = wq_size / wqe_size;
+ if (wqe_size > dev->mdev.caps.max_rq_desc_sz) {
+ mlx5_ib_dbg(dev, "wqe_size %d, max %d\n",
+ wqe_size,
+ dev->mdev.caps.max_rq_desc_sz);
+ return -EINVAL;
+ }
+ qp->rq.wqe_shift = ilog2(wqe_size);
+ qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
+ qp->rq.max_post = qp->rq.wqe_cnt;
+ }
+ }
+
+ return 0;
+}
+
+static int sq_overhead(enum ib_qp_type qp_type)
+{
+ int size;
+
+ switch (qp_type) {
+ case IB_QPT_XRC_INI:
+ size = sizeof(struct mlx5_wqe_xrc_seg);
+ /* fall through */
+ case IB_QPT_RC:
+ size += sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_atomic_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg);
+ break;
+
+ case IB_QPT_UC:
+ size = sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg);
+ break;
+
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ size = sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_datagram_seg);
+ break;
+
+ case MLX5_IB_QPT_REG_UMR:
+ size = sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+ sizeof(struct mlx5_mkey_seg);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return size;
+}
+
+static int calc_send_wqe(struct ib_qp_init_attr *attr)
+{
+ int inl_size = 0;
+ int size;
+
+ size = sq_overhead(attr->qp_type);
+ if (size < 0)
+ return size;
+
+ if (attr->cap.max_inline_data) {
+ inl_size = size + sizeof(struct mlx5_wqe_inline_seg) +
+ attr->cap.max_inline_data;
+ }
+
+ size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
+
+ return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
+}
+
+static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
+ struct mlx5_ib_qp *qp)
+{
+ int wqe_size;
+ int wq_size;
+
+ if (!attr->cap.max_send_wr)
+ return 0;
+
+ wqe_size = calc_send_wqe(attr);
+ mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size);
+ if (wqe_size < 0)
+ return wqe_size;
+
+ if (wqe_size > dev->mdev.caps.max_sq_desc_sz) {
+ mlx5_ib_dbg(dev, "\n");
+ return -EINVAL;
+ }
+
+ qp->max_inline_data = wqe_size - sq_overhead(attr->qp_type) -
+ sizeof(struct mlx5_wqe_inline_seg);
+ attr->cap.max_inline_data = qp->max_inline_data;
+
+ wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
+ qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
+ qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
+ qp->sq.max_gs = attr->cap.max_send_sge;
+ qp->sq.max_post = 1 << ilog2(wq_size / wqe_size);
+
+ return wq_size;
+}
+
+static int set_user_buf_size(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_qp *qp,
+ struct mlx5_ib_create_qp *ucmd)
+{
+ int desc_sz = 1 << qp->sq.wqe_shift;
+
+ if (desc_sz > dev->mdev.caps.max_sq_desc_sz) {
+ mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
+ desc_sz, dev->mdev.caps.max_sq_desc_sz);
+ return -EINVAL;
+ }
+
+ if (ucmd->sq_wqe_count && ((1 << ilog2(ucmd->sq_wqe_count)) != ucmd->sq_wqe_count)) {
+ mlx5_ib_warn(dev, "sq_wqe_count %d, sq_wqe_count %d\n",
+ ucmd->sq_wqe_count, ucmd->sq_wqe_count);
+ return -EINVAL;
+ }
+
+ qp->sq.wqe_cnt = ucmd->sq_wqe_count;
+
+ if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) {
+ mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n",
+ qp->sq.wqe_cnt, dev->mdev.caps.max_wqes);
+ return -EINVAL;
+ }
+
+ qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
+ (qp->sq.wqe_cnt << 6);
+
+ return 0;
+}
+
+static int qp_has_rq(struct ib_qp_init_attr *attr)
+{
+ if (attr->qp_type == IB_QPT_XRC_INI ||
+ attr->qp_type == IB_QPT_XRC_TGT || attr->srq ||
+ attr->qp_type == MLX5_IB_QPT_REG_UMR ||
+ !attr->cap.max_recv_wr)
+ return 0;
+
+ return 1;
+}
+
+static int alloc_high_class_uuar(struct mlx5_uuar_info *uuari)
+{
+ int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+ int start_uuar;
+ int i;
+
+ start_uuar = nuuars - uuari->num_low_latency_uuars;
+ for (i = start_uuar; i < nuuars; i++) {
+ if (!test_bit(i, uuari->bitmap)) {
+ set_bit(i, uuari->bitmap);
+ uuari->count[i]++;
+ return i;
+ }
+ }
+
+ return -ENOMEM;
+}
+
+static int alloc_med_class_uuar(struct mlx5_uuar_info *uuari)
+{
+ int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+ int minidx = 1;
+ int uuarn;
+ int end;
+ int i;
+
+ end = nuuars - uuari->num_low_latency_uuars;
+
+ for (i = 1; i < end; i++) {
+ uuarn = i & 3;
+ if (uuarn == 2 || uuarn == 3)
+ continue;
+
+ if (uuari->count[i] < uuari->count[minidx])
+ minidx = i;
+ }
+
+ uuari->count[minidx]++;
+ return minidx;
+}
+
+static int alloc_uuar(struct mlx5_uuar_info *uuari,
+ enum mlx5_ib_latency_class lat)
+{
+ int uuarn = -EINVAL;
+
+ mutex_lock(&uuari->lock);
+ switch (lat) {
+ case MLX5_IB_LATENCY_CLASS_LOW:
+ uuarn = 0;
+ uuari->count[uuarn]++;
+ break;
+
+ case MLX5_IB_LATENCY_CLASS_MEDIUM:
+ uuarn = alloc_med_class_uuar(uuari);
+ break;
+
+ case MLX5_IB_LATENCY_CLASS_HIGH:
+ uuarn = alloc_high_class_uuar(uuari);
+ break;
+
+ case MLX5_IB_LATENCY_CLASS_FAST_PATH:
+ uuarn = 2;
+ break;
+ }
+ mutex_unlock(&uuari->lock);
+
+ return uuarn;
+}
+
+static void free_med_class_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+ clear_bit(uuarn, uuari->bitmap);
+ --uuari->count[uuarn];
+}
+
+static void free_high_class_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+ clear_bit(uuarn, uuari->bitmap);
+ --uuari->count[uuarn];
+}
+
+static void free_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+ int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+ int high_uuar = nuuars - uuari->num_low_latency_uuars;
+
+ mutex_lock(&uuari->lock);
+ if (uuarn == 0) {
+ --uuari->count[uuarn];
+ goto out;
+ }
+
+ if (uuarn < high_uuar) {
+ free_med_class_uuar(uuari, uuarn);
+ goto out;
+ }
+
+ free_high_class_uuar(uuari, uuarn);
+
+out:
+ mutex_unlock(&uuari->lock);
+}
+
+static enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state)
+{
+ switch (state) {
+ case IB_QPS_RESET: return MLX5_QP_STATE_RST;
+ case IB_QPS_INIT: return MLX5_QP_STATE_INIT;
+ case IB_QPS_RTR: return MLX5_QP_STATE_RTR;
+ case IB_QPS_RTS: return MLX5_QP_STATE_RTS;
+ case IB_QPS_SQD: return MLX5_QP_STATE_SQD;
+ case IB_QPS_SQE: return MLX5_QP_STATE_SQER;
+ case IB_QPS_ERR: return MLX5_QP_STATE_ERR;
+ default: return -1;
+ }
+}
+
+static int to_mlx5_st(enum ib_qp_type type)
+{
+ switch (type) {
+ case IB_QPT_RC: return MLX5_QP_ST_RC;
+ case IB_QPT_UC: return MLX5_QP_ST_UC;
+ case IB_QPT_UD: return MLX5_QP_ST_UD;
+ case MLX5_IB_QPT_REG_UMR: return MLX5_QP_ST_REG_UMR;
+ case IB_QPT_XRC_INI:
+ case IB_QPT_XRC_TGT: return MLX5_QP_ST_XRC;
+ case IB_QPT_SMI: return MLX5_QP_ST_QP0;
+ case IB_QPT_GSI: return MLX5_QP_ST_QP1;
+ case IB_QPT_RAW_IPV6: return MLX5_QP_ST_RAW_IPV6;
+ case IB_QPT_RAW_ETHERTYPE: return MLX5_QP_ST_RAW_ETHERTYPE;
+ case IB_QPT_RAW_PACKET:
+ case IB_QPT_MAX:
+ default: return -EINVAL;
+ }
+}
+
+static int uuarn_to_uar_index(struct mlx5_uuar_info *uuari, int uuarn)
+{
+ return uuari->uars[uuarn / MLX5_BF_REGS_PER_PAGE].index;
+}
+
+static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+ struct mlx5_ib_qp *qp, struct ib_udata *udata,
+ struct mlx5_create_qp_mbox_in **in,
+ struct mlx5_ib_create_qp_resp *resp, int *inlen)
+{
+ struct mlx5_ib_ucontext *context;
+ struct mlx5_ib_create_qp ucmd;
+ int page_shift;
+ int uar_index;
+ int npages;
+ u32 offset;
+ int uuarn;
+ int ncont;
+ int err;
+
+ err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd));
+ if (err) {
+ mlx5_ib_dbg(dev, "copy failed\n");
+ return err;
+ }
+
+ context = to_mucontext(pd->uobject->context);
+ /*
+ * TBD: should come from the verbs when we have the API
+ */
+ uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_HIGH);
+ if (uuarn < 0) {
+ mlx5_ib_dbg(dev, "failed to allocate low latency UUAR\n");
+ mlx5_ib_dbg(dev, "reverting to high latency\n");
+ uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_LOW);
+ if (uuarn < 0) {
+ mlx5_ib_dbg(dev, "uuar allocation failed\n");
+ return uuarn;
+ }
+ }
+
+ uar_index = uuarn_to_uar_index(&context->uuari, uuarn);
+ mlx5_ib_dbg(dev, "uuarn 0x%x, uar_index 0x%x\n", uuarn, uar_index);
+
+ err = set_user_buf_size(dev, qp, &ucmd);
+ if (err)
+ goto err_uuar;
+
+ qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
+ qp->buf_size, 0, 0);
+ if (IS_ERR(qp->umem)) {
+ mlx5_ib_dbg(dev, "umem_get failed\n");
+ err = PTR_ERR(qp->umem);
+ goto err_uuar;
+ }
+
+ mlx5_ib_cont_pages(qp->umem, ucmd.buf_addr, &npages, &page_shift,
+ &ncont, NULL);
+ err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, &offset);
+ if (err) {
+ mlx5_ib_warn(dev, "bad offset\n");
+ goto err_umem;
+ }
+ mlx5_ib_dbg(dev, "addr 0x%llx, size %d, npages %d, page_shift %d, ncont %d, offset %d\n",
+ ucmd.buf_addr, qp->buf_size, npages, page_shift, ncont, offset);
+
+ *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
+ *in = mlx5_vzalloc(*inlen);
+ if (!*in) {
+ err = -ENOMEM;
+ goto err_umem;
+ }
+ mlx5_ib_populate_pas(dev, qp->umem, page_shift, (*in)->pas, 0);
+ (*in)->ctx.log_pg_sz_remote_qpn =
+ cpu_to_be32((page_shift - PAGE_SHIFT) << 24);
+ (*in)->ctx.params2 = cpu_to_be32(offset << 6);
+
+ (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index);
+ resp->uuar_index = uuarn;
+ qp->uuarn = uuarn;
+
+ err = mlx5_ib_db_map_user(context, ucmd.db_addr, &qp->db);
+ if (err) {
+ mlx5_ib_dbg(dev, "map failed\n");
+ goto err_free;
+ }
+
+ err = ib_copy_to_udata(udata, resp, sizeof(*resp));
+ if (err) {
+ mlx5_ib_dbg(dev, "copy failed\n");
+ goto err_unmap;
+ }
+ qp->create_type = MLX5_QP_USER;
+
+ return 0;
+
+err_unmap:
+ mlx5_ib_db_unmap_user(context, &qp->db);
+
+err_free:
+ mlx5_vfree(*in);
+
+err_umem:
+ ib_umem_release(qp->umem);
+
+err_uuar:
+ free_uuar(&context->uuari, uuarn);
+ return err;
+}
+
+static void destroy_qp_user(struct ib_pd *pd, struct mlx5_ib_qp *qp)
+{
+ struct mlx5_ib_ucontext *context;
+
+ context = to_mucontext(pd->uobject->context);
+ mlx5_ib_db_unmap_user(context, &qp->db);
+ ib_umem_release(qp->umem);
+ free_uuar(&context->uuari, qp->uuarn);
+}
+
+static int create_kernel_qp(struct mlx5_ib_dev *dev,
+ struct ib_qp_init_attr *init_attr,
+ struct mlx5_ib_qp *qp,
+ struct mlx5_create_qp_mbox_in **in, int *inlen)
+{
+ enum mlx5_ib_latency_class lc = MLX5_IB_LATENCY_CLASS_LOW;
+ struct mlx5_uuar_info *uuari;
+ int uar_index;
+ int uuarn;
+ int err;
+
+ uuari = &dev->mdev.priv.uuari;
+ if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
+ qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
+
+ if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
+ lc = MLX5_IB_LATENCY_CLASS_FAST_PATH;
+
+ uuarn = alloc_uuar(uuari, lc);
+ if (uuarn < 0) {
+ mlx5_ib_dbg(dev, "\n");
+ return -ENOMEM;
+ }
+
+ qp->bf = &uuari->bfs[uuarn];
+ uar_index = qp->bf->uar->index;
+
+ err = calc_sq_size(dev, init_attr, qp);
+ if (err < 0) {
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ goto err_uuar;
+ }
+
+ qp->rq.offset = 0;
+ qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
+ qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift);
+
+ err = mlx5_buf_alloc(&dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf);
+ if (err) {
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ goto err_uuar;
+ }
+
+ qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt);
+ *inlen = sizeof(**in) + sizeof(*(*in)->pas) * qp->buf.npages;
+ *in = mlx5_vzalloc(*inlen);
+ if (!*in) {
+ err = -ENOMEM;
+ goto err_buf;
+ }
+ (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index);
+ (*in)->ctx.log_pg_sz_remote_qpn = cpu_to_be32((qp->buf.page_shift - PAGE_SHIFT) << 24);
+ /* Set "fast registration enabled" for all kernel QPs */
+ (*in)->ctx.params1 |= cpu_to_be32(1 << 11);
+ (*in)->ctx.sq_crq_size |= cpu_to_be16(1 << 4);
+
+ mlx5_fill_page_array(&qp->buf, (*in)->pas);
+
+ err = mlx5_db_alloc(&dev->mdev, &qp->db);
+ if (err) {
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ goto err_free;
+ }
+
+ qp->db.db[0] = 0;
+ qp->db.db[1] = 0;
+
+ qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid), GFP_KERNEL);
+ qp->sq.wr_data = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data), GFP_KERNEL);
+ qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(*qp->rq.wrid), GFP_KERNEL);
+ qp->sq.w_list = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.w_list), GFP_KERNEL);
+ qp->sq.wqe_head = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wqe_head), GFP_KERNEL);
+
+ if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid ||
+ !qp->sq.w_list || !qp->sq.wqe_head) {
+ err = -ENOMEM;
+ goto err_wrid;
+ }
+ qp->create_type = MLX5_QP_KERNEL;
+
+ return 0;
+
+err_wrid:
+ mlx5_db_free(&dev->mdev, &qp->db);
+ kfree(qp->sq.wqe_head);
+ kfree(qp->sq.w_list);
+ kfree(qp->sq.wrid);
+ kfree(qp->sq.wr_data);
+ kfree(qp->rq.wrid);
+
+err_free:
+ mlx5_vfree(*in);
+
+err_buf:
+ mlx5_buf_free(&dev->mdev, &qp->buf);
+
+err_uuar:
+ free_uuar(&dev->mdev.priv.uuari, uuarn);
+ return err;
+}
+
+static void destroy_qp_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
+{
+ mlx5_db_free(&dev->mdev, &qp->db);
+ kfree(qp->sq.wqe_head);
+ kfree(qp->sq.w_list);
+ kfree(qp->sq.wrid);
+ kfree(qp->sq.wr_data);
+ kfree(qp->rq.wrid);
+ mlx5_buf_free(&dev->mdev, &qp->buf);
+ free_uuar(&dev->mdev.priv.uuari, qp->bf->uuarn);
+}
+
+static __be32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr)
+{
+ if (attr->srq || (attr->qp_type == IB_QPT_XRC_TGT) ||
+ (attr->qp_type == IB_QPT_XRC_INI))
+ return cpu_to_be32(MLX5_SRQ_RQ);
+ else if (!qp->has_rq)
+ return cpu_to_be32(MLX5_ZERO_LEN_RQ);
+ else
+ return cpu_to_be32(MLX5_NON_ZERO_RQ);
+}
+
+static int is_connected(enum ib_qp_type qp_type)
+{
+ if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC)
+ return 1;
+
+ return 0;
+}
+
+static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, struct mlx5_ib_qp *qp)
+{
+ struct mlx5_ib_resources *devr = &dev->devr;
+ struct mlx5_ib_create_qp_resp resp;
+ struct mlx5_create_qp_mbox_in *in;
+ struct mlx5_ib_create_qp ucmd;
+ int inlen = sizeof(*in);
+ int err;
+
+ mutex_init(&qp->mutex);
+ spin_lock_init(&qp->sq.lock);
+ spin_lock_init(&qp->rq.lock);
+
+ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+ qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
+
+ if (pd && pd->uobject) {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+ mlx5_ib_dbg(dev, "copy failed\n");
+ return -EFAULT;
+ }
+
+ qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE);
+ qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
+ } else {
+ qp->wq_sig = !!wq_signature;
+ }
+
+ qp->has_rq = qp_has_rq(init_attr);
+ err = set_rq_size(dev, &init_attr->cap, qp->has_rq,
+ qp, (pd && pd->uobject) ? &ucmd : NULL);
+ if (err) {
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ return err;
+ }
+
+ if (pd) {
+ if (pd->uobject) {
+ mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count);
+ if (ucmd.rq_wqe_shift != qp->rq.wqe_shift ||
+ ucmd.rq_wqe_count != qp->rq.wqe_cnt) {
+ mlx5_ib_dbg(dev, "invalid rq params\n");
+ return -EINVAL;
+ }
+ if (ucmd.sq_wqe_count > dev->mdev.caps.max_wqes) {
+ mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n",
+ ucmd.sq_wqe_count, dev->mdev.caps.max_wqes);
+ return -EINVAL;
+ }
+ err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen);
+ if (err)
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ } else {
+ err = create_kernel_qp(dev, init_attr, qp, &in, &inlen);
+ if (err)
+ mlx5_ib_dbg(dev, "err %d\n", err);
+ else
+ qp->pa_lkey = to_mpd(pd)->pa_lkey;
+ }
+
+ if (err)
+ return err;
+ } else {
+ in = mlx5_vzalloc(sizeof(*in));
+ if (!in)
+ return -ENOMEM;
+
+ qp->create_type = MLX5_QP_EMPTY;
+ }
+
+ if (is_sqp(init_attr->qp_type))
+ qp->port = init_attr->port_num;
+
+ in->ctx.flags = cpu_to_be32(to_mlx5_st(init_attr->qp_type) << 16 |
+ MLX5_QP_PM_MIGRATED << 11);
+
+ if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR)
+ in->ctx.flags_pd = cpu_to_be32(to_mpd(pd ? pd : devr->p0)->pdn);
+ else
+ in->ctx.flags_pd = cpu_to_be32(MLX5_QP_LAT_SENSITIVE);
+
+ if (qp->wq_sig)
+ in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG);
+
+ if (qp->scat_cqe && is_connected(init_attr->qp_type)) {
+ int rcqe_sz;
+ int scqe_sz;
+
+ rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq);
+ scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq);
+
+ if (rcqe_sz == 128)
+ in->ctx.cs_res = MLX5_RES_SCAT_DATA64_CQE;
+ else
+ in->ctx.cs_res = MLX5_RES_SCAT_DATA32_CQE;
+
+ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) {
+ if (scqe_sz == 128)
+ in->ctx.cs_req = MLX5_REQ_SCAT_DATA64_CQE;
+ else
+ in->ctx.cs_req = MLX5_REQ_SCAT_DATA32_CQE;
+ }
+ }
+
+ if (qp->rq.wqe_cnt) {
+ in->ctx.rq_size_stride = (qp->rq.wqe_shift - 4);
+ in->ctx.rq_size_stride |= ilog2(qp->rq.wqe_cnt) << 3;
+ }
+
+ in->ctx.rq_type_srqn = get_rx_type(qp, init_attr);
+
+ if (qp->sq.wqe_cnt)
+ in->ctx.sq_crq_size |= cpu_to_be16(ilog2(qp->sq.wqe_cnt) << 11);
+ else
+ in->ctx.sq_crq_size |= cpu_to_be16(0x8000);
+
+ /* Set default resources */
+ switch (init_attr->qp_type) {
+ case IB_QPT_XRC_TGT:
+ in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+ in->ctx.cqn_send = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+ in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+ in->ctx.xrcd = cpu_to_be32(to_mxrcd(init_attr->xrcd)->xrcdn);
+ break;
+ case IB_QPT_XRC_INI:
+ in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+ in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn);
+ in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+ break;
+ default:
+ if (init_attr->srq) {
+ in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x0)->xrcdn);
+ in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(init_attr->srq)->msrq.srqn);
+ } else {
+ in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn);
+ in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+ }
+ }
+
+ if (init_attr->send_cq)
+ in->ctx.cqn_send = cpu_to_be32(to_mcq(init_attr->send_cq)->mcq.cqn);
+
+ if (init_attr->recv_cq)
+ in->ctx.cqn_recv = cpu_to_be32(to_mcq(init_attr->recv_cq)->mcq.cqn);
+
+ in->ctx.db_rec_addr = cpu_to_be64(qp->db.dma);
+
+ err = mlx5_core_create_qp(&dev->mdev, &qp->mqp, in, inlen);
+ if (err) {
+ mlx5_ib_dbg(dev, "create qp failed\n");
+ goto err_create;
+ }
+
+ mlx5_vfree(in);
+ /* Hardware wants QPN written in big-endian order (after
+ * shifting) for send doorbell. Precompute this value to save
+ * a little bit when posting sends.
+ */
+ qp->doorbell_qpn = swab32(qp->mqp.qpn << 8);
+
+ qp->mqp.event = mlx5_ib_qp_event;
+
+ return 0;
+
+err_create:
+ if (qp->create_type == MLX5_QP_USER)
+ destroy_qp_user(pd, qp);
+ else if (qp->create_type == MLX5_QP_KERNEL)
+ destroy_qp_kernel(dev, qp);
+
+ mlx5_vfree(in);
+ return err;
+}
+
+static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
+ __acquires(&send_cq->lock) __acquires(&recv_cq->lock)
+{
+ if (send_cq) {
+ if (recv_cq) {
+ if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
+ spin_lock_irq(&send_cq->lock);
+ spin_lock_nested(&recv_cq->lock,
+ SINGLE_DEPTH_NESTING);
+ } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
+ spin_lock_irq(&send_cq->lock);
+ __acquire(&recv_cq->lock);
+ } else {
+ spin_lock_irq(&recv_cq->lock);
+ spin_lock_nested(&send_cq->lock,
+ SINGLE_DEPTH_NESTING);
+ }
+ } else {
+ spin_lock_irq(&send_cq->lock);
+ }
+ } else if (recv_cq) {
+ spin_lock_irq(&recv_cq->lock);
+ }
+}
+
+static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
+ __releases(&send_cq->lock) __releases(&recv_cq->lock)
+{
+ if (send_cq) {
+ if (recv_cq) {
+ if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
+ spin_unlock(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+ } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
+ __release(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+ } else {
+ spin_unlock(&send_cq->lock);
+ spin_unlock_irq(&recv_cq->lock);
+ }
+ } else {
+ spin_unlock_irq(&send_cq->lock);
+ }
+ } else if (recv_cq) {
+ spin_unlock_irq(&recv_cq->lock);
+ }
+}
+
+static struct mlx5_ib_pd *get_pd(struct mlx5_ib_qp *qp)
+{
+ return to_mpd(qp->ibqp.pd);
+}
+
+static void get_cqs(struct mlx5_ib_qp *qp,
+ struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq)
+{
+ switch (qp->ibqp.qp_type) {
+ case IB_QPT_XRC_TGT:
+ *send_cq = NULL;
+ *recv_cq = NULL;
+ break;
+ case MLX5_IB_QPT_REG_UMR:
+ case IB_QPT_XRC_INI:
+ *send_cq = to_mcq(qp->ibqp.send_cq);
+ *recv_cq = NULL;
+ break;
+
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ case IB_QPT_RC:
+ case IB_QPT_UC:
+ case IB_QPT_UD:
+ case IB_QPT_RAW_IPV6:
+ case IB_QPT_RAW_ETHERTYPE:
+ *send_cq = to_mcq(qp->ibqp.send_cq);
+ *recv_cq = to_mcq(qp->ibqp.recv_cq);
+ break;
+
+ case IB_QPT_RAW_PACKET:
+ case IB_QPT_MAX:
+ default:
+ *send_cq = NULL;
+ *recv_cq = NULL;
+ break;
+ }
+}
+
+static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
+{
+ struct mlx5_ib_cq *send_cq, *recv_cq;
+ struct mlx5_modify_qp_mbox_in *in;
+ int err;
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in)
+ return;
+ if (qp->state != IB_QPS_RESET)
+ if (mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(qp->state),
+ MLX5_QP_STATE_RST, in, sizeof(*in), &qp->mqp))
+ mlx5_ib_warn(dev, "mlx5_ib: modify QP %06x to RESET failed\n",
+ qp->mqp.qpn);
+
+ get_cqs(qp, &send_cq, &recv_cq);
+
+ if (qp->create_type == MLX5_QP_KERNEL) {
+ mlx5_ib_lock_cqs(send_cq, recv_cq);
+ __mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn,
+ qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
+ if (send_cq != recv_cq)
+ __mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+ mlx5_ib_unlock_cqs(send_cq, recv_cq);
+ }
+
+ err = mlx5_core_destroy_qp(&dev->mdev, &qp->mqp);
+ if (err)
+ mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n", qp->mqp.qpn);
+ kfree(in);
+
+
+ if (qp->create_type == MLX5_QP_KERNEL)
+ destroy_qp_kernel(dev, qp);
+ else if (qp->create_type == MLX5_QP_USER)
+ destroy_qp_user(&get_pd(qp)->ibpd, qp);
+}
+
+static const char *ib_qp_type_str(enum ib_qp_type type)
+{
+ switch (type) {
+ case IB_QPT_SMI:
+ return "IB_QPT_SMI";
+ case IB_QPT_GSI:
+ return "IB_QPT_GSI";
+ case IB_QPT_RC:
+ return "IB_QPT_RC";
+ case IB_QPT_UC:
+ return "IB_QPT_UC";
+ case IB_QPT_UD:
+ return "IB_QPT_UD";
+ case IB_QPT_RAW_IPV6:
+ return "IB_QPT_RAW_IPV6";
+ case IB_QPT_RAW_ETHERTYPE:
+ return "IB_QPT_RAW_ETHERTYPE";
+ case IB_QPT_XRC_INI:
+ return "IB_QPT_XRC_INI";
+ case IB_QPT_XRC_TGT:
+ return "IB_QPT_XRC_TGT";
+ case IB_QPT_RAW_PACKET:
+ return "IB_QPT_RAW_PACKET";
+ case MLX5_IB_QPT_REG_UMR:
+ return "MLX5_IB_QPT_REG_UMR";
+ case IB_QPT_MAX:
+ default:
+ return "Invalid QP type";
+ }
+}
+
+struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev;
+ struct mlx5_ib_qp *qp;
+ u16 xrcdn = 0;
+ int err;
+
+ if (pd) {
+ dev = to_mdev(pd->device);
+ } else {
+ /* being cautious here */
+ if (init_attr->qp_type != IB_QPT_XRC_TGT &&
+ init_attr->qp_type != MLX5_IB_QPT_REG_UMR) {
+ pr_warn("%s: no PD for transport %s\n", __func__,
+ ib_qp_type_str(init_attr->qp_type));
+ return ERR_PTR(-EINVAL);
+ }
+ dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
+ }
+
+ switch (init_attr->qp_type) {
+ case IB_QPT_XRC_TGT:
+ case IB_QPT_XRC_INI:
+ if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) {
+ mlx5_ib_dbg(dev, "XRC not supported\n");
+ return ERR_PTR(-ENOSYS);
+ }
+ init_attr->recv_cq = NULL;
+ if (init_attr->qp_type == IB_QPT_XRC_TGT) {
+ xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
+ init_attr->send_cq = NULL;
+ }
+
+ /* fall through */
+ case IB_QPT_RC:
+ case IB_QPT_UC:
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ case MLX5_IB_QPT_REG_UMR:
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return ERR_PTR(-ENOMEM);
+
+ err = create_qp_common(dev, pd, init_attr, udata, qp);
+ if (err) {
+ mlx5_ib_dbg(dev, "create_qp_common failed\n");
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ if (is_qp0(init_attr->qp_type))
+ qp->ibqp.qp_num = 0;
+ else if (is_qp1(init_attr->qp_type))
+ qp->ibqp.qp_num = 1;
+ else
+ qp->ibqp.qp_num = qp->mqp.qpn;
+
+ mlx5_ib_dbg(dev, "ib qpnum 0x%x, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x\n",
+ qp->ibqp.qp_num, qp->mqp.qpn, to_mcq(init_attr->recv_cq)->mcq.cqn,
+ to_mcq(init_attr->send_cq)->mcq.cqn);
+
+ qp->xrcdn = xrcdn;
+
+ break;
+
+ case IB_QPT_RAW_IPV6:
+ case IB_QPT_RAW_ETHERTYPE:
+ case IB_QPT_RAW_PACKET:
+ case IB_QPT_MAX:
+ default:
+ mlx5_ib_dbg(dev, "unsupported qp type %d\n",
+ init_attr->qp_type);
+ /* Don't support raw QPs */
+ return ERR_PTR(-EINVAL);
+ }
+
+ return &qp->ibqp;
+}
+
+int mlx5_ib_destroy_qp(struct ib_qp *qp)
+{
+ struct mlx5_ib_dev *dev = to_mdev(qp->device);
+ struct mlx5_ib_qp *mqp = to_mqp(qp);
+
+ destroy_qp_common(dev, mqp);
+
+ kfree(mqp);
+
+ return 0;
+}
+
+static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr,
+ int attr_mask)
+{
+ u32 hw_access_flags = 0;
+ u8 dest_rd_atomic;
+ u32 access_flags;
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+ dest_rd_atomic = attr->max_dest_rd_atomic;
+ else
+ dest_rd_atomic = qp->resp_depth;
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS)
+ access_flags = attr->qp_access_flags;
+ else
+ access_flags = qp->atomic_rd_en;
+
+ if (!dest_rd_atomic)
+ access_flags &= IB_ACCESS_REMOTE_WRITE;
+
+ if (access_flags & IB_ACCESS_REMOTE_READ)
+ hw_access_flags |= MLX5_QP_BIT_RRE;
+ if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
+ hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX);
+ if (access_flags & IB_ACCESS_REMOTE_WRITE)
+ hw_access_flags |= MLX5_QP_BIT_RWE;
+
+ return cpu_to_be32(hw_access_flags);
+}
+
+enum {
+ MLX5_PATH_FLAG_FL = 1 << 0,
+ MLX5_PATH_FLAG_FREE_AR = 1 << 1,
+ MLX5_PATH_FLAG_COUNTER = 1 << 2,
+};
+
+static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
+{
+ if (rate == IB_RATE_PORT_CURRENT) {
+ return 0;
+ } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) {
+ return -EINVAL;
+ } else {
+ while (rate != IB_RATE_2_5_GBPS &&
+ !(1 << (rate + MLX5_STAT_RATE_OFFSET) &
+ dev->mdev.caps.stat_rate_support))
+ --rate;
+ }
+
+ return rate + MLX5_STAT_RATE_OFFSET;
+}
+
+static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
+ struct mlx5_qp_path *path, u8 port, int attr_mask,
+ u32 path_flags, const struct ib_qp_attr *attr)
+{
+ int err;
+
+ path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0;
+ path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0;
+
+ if (attr_mask & IB_QP_PKEY_INDEX)
+ path->pkey_index = attr->pkey_index;
+
+ path->grh_mlid = ah->src_path_bits & 0x7f;
+ path->rlid = cpu_to_be16(ah->dlid);
+
+ if (ah->ah_flags & IB_AH_GRH) {
+ path->grh_mlid |= 1 << 7;
+ path->mgid_index = ah->grh.sgid_index;
+ path->hop_limit = ah->grh.hop_limit;
+ path->tclass_flowlabel =
+ cpu_to_be32((ah->grh.traffic_class << 20) |
+ (ah->grh.flow_label));
+ memcpy(path->rgid, ah->grh.dgid.raw, 16);
+ }
+
+ err = ib_rate_to_mlx5(dev, ah->static_rate);
+ if (err < 0)
+ return err;
+ path->static_rate = err;
+ path->port = port;
+
+ if (ah->ah_flags & IB_AH_GRH) {
+ if (ah->grh.sgid_index >= dev->mdev.caps.port[port - 1].gid_table_len) {
+ pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n",
+ ah->grh.sgid_index, dev->mdev.caps.port[port - 1].gid_table_len);
+ return -EINVAL;
+ }
+
+ path->grh_mlid |= 1 << 7;
+ path->mgid_index = ah->grh.sgid_index;
+ path->hop_limit = ah->grh.hop_limit;
+ path->tclass_flowlabel =
+ cpu_to_be32((ah->grh.traffic_class << 20) |
+ (ah->grh.flow_label));
+ memcpy(path->rgid, ah->grh.dgid.raw, 16);
+ }
+
+ if (attr_mask & IB_QP_TIMEOUT)
+ path->ackto_lt = attr->timeout << 3;
+
+ path->sl = ah->sl & 0xf;
+
+ return 0;
+}
+
+static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = {
+ [MLX5_QP_STATE_INIT] = {
+ [MLX5_QP_STATE_INIT] = {
+ [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE |
+ MLX5_QP_OPTPAR_RAE |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PKEY_INDEX |
+ MLX5_QP_OPTPAR_PRI_PORT,
+ [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PKEY_INDEX |
+ MLX5_QP_OPTPAR_PRI_PORT,
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX |
+ MLX5_QP_OPTPAR_Q_KEY |
+ MLX5_QP_OPTPAR_PRI_PORT,
+ },
+ [MLX5_QP_STATE_RTR] = {
+ [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+ MLX5_QP_OPTPAR_RRE |
+ MLX5_QP_OPTPAR_RAE |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PKEY_INDEX,
+ [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PKEY_INDEX,
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX |
+ MLX5_QP_OPTPAR_Q_KEY,
+ [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX |
+ MLX5_QP_OPTPAR_Q_KEY,
+ },
+ },
+ [MLX5_QP_STATE_RTR] = {
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+ MLX5_QP_OPTPAR_RRE |
+ MLX5_QP_OPTPAR_RAE |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PM_STATE |
+ MLX5_QP_OPTPAR_RNR_TIMEOUT,
+ [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PM_STATE,
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
+ },
+ },
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE |
+ MLX5_QP_OPTPAR_RAE |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_RNR_TIMEOUT |
+ MLX5_QP_OPTPAR_PM_STATE,
+ [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_PM_STATE,
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY |
+ MLX5_QP_OPTPAR_SRQN |
+ MLX5_QP_OPTPAR_CQN_RCV,
+ },
+ },
+ [MLX5_QP_STATE_SQER] = {
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
+ [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
+ },
+ },
+};
+
+static int ib_nr_to_mlx5_nr(int ib_mask)
+{
+ switch (ib_mask) {
+ case IB_QP_STATE:
+ return 0;
+ case IB_QP_CUR_STATE:
+ return 0;
+ case IB_QP_EN_SQD_ASYNC_NOTIFY:
+ return 0;
+ case IB_QP_ACCESS_FLAGS:
+ return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE |
+ MLX5_QP_OPTPAR_RAE;
+ case IB_QP_PKEY_INDEX:
+ return MLX5_QP_OPTPAR_PKEY_INDEX;
+ case IB_QP_PORT:
+ return MLX5_QP_OPTPAR_PRI_PORT;
+ case IB_QP_QKEY:
+ return MLX5_QP_OPTPAR_Q_KEY;
+ case IB_QP_AV:
+ return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH |
+ MLX5_QP_OPTPAR_PRI_PORT;
+ case IB_QP_PATH_MTU:
+ return 0;
+ case IB_QP_TIMEOUT:
+ return MLX5_QP_OPTPAR_ACK_TIMEOUT;
+ case IB_QP_RETRY_CNT:
+ return MLX5_QP_OPTPAR_RETRY_COUNT;
+ case IB_QP_RNR_RETRY:
+ return MLX5_QP_OPTPAR_RNR_RETRY;
+ case IB_QP_RQ_PSN:
+ return 0;
+ case IB_QP_MAX_QP_RD_ATOMIC:
+ return MLX5_QP_OPTPAR_SRA_MAX;
+ case IB_QP_ALT_PATH:
+ return MLX5_QP_OPTPAR_ALT_ADDR_PATH;
+ case IB_QP_MIN_RNR_TIMER:
+ return MLX5_QP_OPTPAR_RNR_TIMEOUT;
+ case IB_QP_SQ_PSN:
+ return 0;
+ case IB_QP_MAX_DEST_RD_ATOMIC:
+ return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE;
+ case IB_QP_PATH_MIG_STATE:
+ return MLX5_QP_OPTPAR_PM_STATE;
+ case IB_QP_CAP:
+ return 0;
+ case IB_QP_DEST_QPN:
+ return 0;
+ }
+ return 0;
+}
+
+static int ib_mask_to_mlx5_opt(int ib_mask)
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < 8 * sizeof(int); i++) {
+ if ((1 << i) & ib_mask)
+ result |= ib_nr_to_mlx5_nr(1 << i);
+ }
+
+ return result;
+}
+
+static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
+ const struct ib_qp_attr *attr, int attr_mask,
+ enum ib_qp_state cur_state, enum ib_qp_state new_state)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ struct mlx5_ib_cq *send_cq, *recv_cq;
+ struct mlx5_qp_context *context;
+ struct mlx5_modify_qp_mbox_in *in;
+ struct mlx5_ib_pd *pd;
+ enum mlx5_qp_state mlx5_cur, mlx5_new;
+ enum mlx5_qp_optpar optpar;
+ int sqd_event;
+ int mlx5_st;
+ int err;
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ context = &in->ctx;
+ err = to_mlx5_st(ibqp->qp_type);
+ if (err < 0)
+ goto out;
+
+ context->flags = cpu_to_be32(err << 16);
+
+ if (!(attr_mask & IB_QP_PATH_MIG_STATE)) {
+ context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
+ } else {
+ switch (attr->path_mig_state) {
+ case IB_MIG_MIGRATED:
+ context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
+ break;
+ case IB_MIG_REARM:
+ context->flags |= cpu_to_be32(MLX5_QP_PM_REARM << 11);
+ break;
+ case IB_MIG_ARMED:
+ context->flags |= cpu_to_be32(MLX5_QP_PM_ARMED << 11);
+ break;
+ }
+ }
+
+ if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
+ context->mtu_msgmax = (IB_MTU_256 << 5) | 8;
+ } else if (ibqp->qp_type == IB_QPT_UD ||
+ ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
+ context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
+ } else if (attr_mask & IB_QP_PATH_MTU) {
+ if (attr->path_mtu < IB_MTU_256 ||
+ attr->path_mtu > IB_MTU_4096) {
+ mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu);
+ err = -EINVAL;
+ goto out;
+ }
+ context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev.caps.log_max_msg;
+ }
+
+ if (attr_mask & IB_QP_DEST_QPN)
+ context->log_pg_sz_remote_qpn = cpu_to_be32(attr->dest_qp_num);
+
+ if (attr_mask & IB_QP_PKEY_INDEX)
+ context->pri_path.pkey_index = attr->pkey_index;
+
+ /* todo implement counter_index functionality */
+
+ if (is_sqp(ibqp->qp_type))
+ context->pri_path.port = qp->port;
+
+ if (attr_mask & IB_QP_PORT)
+ context->pri_path.port = attr->port_num;
+
+ if (attr_mask & IB_QP_AV) {
+ err = mlx5_set_path(dev, &attr->ah_attr, &context->pri_path,
+ attr_mask & IB_QP_PORT ? attr->port_num : qp->port,
+ attr_mask, 0, attr);
+ if (err)
+ goto out;
+ }
+
+ if (attr_mask & IB_QP_TIMEOUT)
+ context->pri_path.ackto_lt |= attr->timeout << 3;
+
+ if (attr_mask & IB_QP_ALT_PATH) {
+ err = mlx5_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
+ attr->alt_port_num, attr_mask, 0, attr);
+ if (err)
+ goto out;
+ }
+
+ pd = get_pd(qp);
+ get_cqs(qp, &send_cq, &recv_cq);
+
+ context->flags_pd = cpu_to_be32(pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn);
+ context->cqn_send = send_cq ? cpu_to_be32(send_cq->mcq.cqn) : 0;
+ context->cqn_recv = recv_cq ? cpu_to_be32(recv_cq->mcq.cqn) : 0;
+ context->params1 = cpu_to_be32(MLX5_IB_ACK_REQ_FREQ << 28);
+
+ if (attr_mask & IB_QP_RNR_RETRY)
+ context->params1 |= cpu_to_be32(attr->rnr_retry << 13);
+
+ if (attr_mask & IB_QP_RETRY_CNT)
+ context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
+
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ if (attr->max_rd_atomic)
+ context->params1 |=
+ cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
+ }
+
+ if (attr_mask & IB_QP_SQ_PSN)
+ context->next_send_psn = cpu_to_be32(attr->sq_psn);
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ if (attr->max_dest_rd_atomic)
+ context->params2 |=
+ cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
+ }
+
+ if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC))
+ context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask);
+
+ if (attr_mask & IB_QP_MIN_RNR_TIMER)
+ context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
+
+ if (attr_mask & IB_QP_RQ_PSN)
+ context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
+
+ if (attr_mask & IB_QP_QKEY)
+ context->qkey = cpu_to_be32(attr->qkey);
+
+ if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+ context->db_rec_addr = cpu_to_be64(qp->db.dma);
+
+ if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD &&
+ attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify)
+ sqd_event = 1;
+ else
+ sqd_event = 0;
+
+ if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+ context->sq_crq_size |= cpu_to_be16(1 << 4);
+
+
+ mlx5_cur = to_mlx5_state(cur_state);
+ mlx5_new = to_mlx5_state(new_state);
+ mlx5_st = to_mlx5_st(ibqp->qp_type);
+ if (mlx5_cur < 0 || mlx5_new < 0 || mlx5_st < 0)
+ goto out;
+
+ optpar = ib_mask_to_mlx5_opt(attr_mask);
+ optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
+ in->optparam = cpu_to_be32(optpar);
+ err = mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(cur_state),
+ to_mlx5_state(new_state), in, sqd_event,
+ &qp->mqp);
+ if (err)
+ goto out;
+
+ qp->state = new_state;
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS)
+ qp->atomic_rd_en = attr->qp_access_flags;
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+ qp->resp_depth = attr->max_dest_rd_atomic;
+ if (attr_mask & IB_QP_PORT)
+ qp->port = attr->port_num;
+ if (attr_mask & IB_QP_ALT_PATH)
+ qp->alt_port = attr->alt_port_num;
+
+ /*
+ * If we moved a kernel QP to RESET, clean up all old CQ
+ * entries and reinitialize the QP.
+ */
+ if (new_state == IB_QPS_RESET && !ibqp->uobject) {
+ mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn,
+ ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+ if (send_cq != recv_cq)
+ mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+
+ qp->rq.head = 0;
+ qp->rq.tail = 0;
+ qp->sq.head = 0;
+ qp->sq.tail = 0;
+ qp->sq.cur_post = 0;
+ qp->sq.last_poll = 0;
+ qp->db.db[MLX5_RCV_DBR] = 0;
+ qp->db.db[MLX5_SND_DBR] = 0;
+ }
+
+out:
+ kfree(in);
+ return err;
+}
+
+int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ enum ib_qp_state cur_state, new_state;
+ int err = -EINVAL;
+ int port;
+
+ mutex_lock(&qp->mutex);
+
+ cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
+ new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
+
+ if (ibqp->qp_type != MLX5_IB_QPT_REG_UMR &&
+ !ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask))
+ goto out;
+
+ if ((attr_mask & IB_QP_PORT) &&
+ (attr->port_num == 0 || attr->port_num > dev->mdev.caps.num_ports))
+ goto out;
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
+ if (attr->pkey_index >= dev->mdev.caps.port[port - 1].pkey_table_len)
+ goto out;
+ }
+
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+ attr->max_rd_atomic > dev->mdev.caps.max_ra_res_qp)
+ goto out;
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+ attr->max_dest_rd_atomic > dev->mdev.caps.max_ra_req_qp)
+ goto out;
+
+ if (cur_state == new_state && cur_state == IB_QPS_RESET) {
+ err = 0;
+ goto out;
+ }
+
+ err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
+
+out:
+ mutex_unlock(&qp->mutex);
+ return err;
+}
+
+static int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
+{
+ struct mlx5_ib_cq *cq;
+ unsigned cur;
+
+ cur = wq->head - wq->tail;
+ if (likely(cur + nreq < wq->max_post))
+ return 0;
+
+ cq = to_mcq(ib_cq);
+ spin_lock(&cq->lock);
+ cur = wq->head - wq->tail;
+ spin_unlock(&cq->lock);
+
+ return cur + nreq >= wq->max_post;
+}
+
+static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
+ u64 remote_addr, u32 rkey)
+{
+ rseg->raddr = cpu_to_be64(remote_addr);
+ rseg->rkey = cpu_to_be32(rkey);
+ rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+ } else {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = 0;
+ }
+}
+
+static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg,
+ struct ib_send_wr *wr)
+{
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->swap_add_mask = cpu_to_be64(wr->wr.atomic.swap_mask);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare_mask = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+}
+
+static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
+ struct ib_send_wr *wr)
+{
+ memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof(struct mlx5_av));
+ dseg->av.dqp_dct = cpu_to_be32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV);
+ dseg->av.key.qkey.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
+static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
+static __be16 get_klm_octo(int npages)
+{
+ return cpu_to_be16(ALIGN(npages, 8) / 2);
+}
+
+static __be64 frwr_mkey_mask(void)
+{
+ u64 result;
+
+ result = MLX5_MKEY_MASK_LEN |
+ MLX5_MKEY_MASK_PAGE_SIZE |
+ MLX5_MKEY_MASK_START_ADDR |
+ MLX5_MKEY_MASK_EN_RINVAL |
+ MLX5_MKEY_MASK_KEY |
+ MLX5_MKEY_MASK_LR |
+ MLX5_MKEY_MASK_LW |
+ MLX5_MKEY_MASK_RR |
+ MLX5_MKEY_MASK_RW |
+ MLX5_MKEY_MASK_A |
+ MLX5_MKEY_MASK_SMALL_FENCE |
+ MLX5_MKEY_MASK_FREE;
+
+ return cpu_to_be64(result);
+}
+
+static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
+ struct ib_send_wr *wr, int li)
+{
+ memset(umr, 0, sizeof(*umr));
+
+ if (li) {
+ umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
+ umr->flags = 1 << 7;
+ return;
+ }
+
+ umr->flags = (1 << 5); /* fail if not free */
+ umr->klm_octowords = get_klm_octo(wr->wr.fast_reg.page_list_len);
+ umr->mkey_mask = frwr_mkey_mask();
+}
+
+static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
+ struct ib_send_wr *wr)
+{
+ struct umr_wr *umrwr = (struct umr_wr *)&wr->wr.fast_reg;
+ u64 mask;
+
+ memset(umr, 0, sizeof(*umr));
+
+ if (!(wr->send_flags & MLX5_IB_SEND_UMR_UNREG)) {
+ umr->flags = 1 << 5; /* fail if not free */
+ umr->klm_octowords = get_klm_octo(umrwr->npages);
+ mask = MLX5_MKEY_MASK_LEN |
+ MLX5_MKEY_MASK_PAGE_SIZE |
+ MLX5_MKEY_MASK_START_ADDR |
+ MLX5_MKEY_MASK_PD |
+ MLX5_MKEY_MASK_LR |
+ MLX5_MKEY_MASK_LW |
+ MLX5_MKEY_MASK_RR |
+ MLX5_MKEY_MASK_RW |
+ MLX5_MKEY_MASK_A |
+ MLX5_MKEY_MASK_FREE;
+ umr->mkey_mask = cpu_to_be64(mask);
+ } else {
+ umr->flags = 2 << 5; /* fail if free */
+ mask = MLX5_MKEY_MASK_FREE;
+ umr->mkey_mask = cpu_to_be64(mask);
+ }
+
+ if (!wr->num_sge)
+ umr->flags |= (1 << 7); /* inline */
+}
+
+static u8 get_umr_flags(int acc)
+{
+ return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) |
+ (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) |
+ (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) |
+ MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
+}
+
+static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr,
+ int li, int *writ)
+{
+ memset(seg, 0, sizeof(*seg));
+ if (li) {
+ seg->status = 1 << 6;
+ return;
+ }
+
+ seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags);
+ *writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE);
+ seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00);
+ seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
+ seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start);
+ seg->len = cpu_to_be64(wr->wr.fast_reg.length);
+ seg->xlt_oct_size = cpu_to_be32((wr->wr.fast_reg.page_list_len + 1) / 2);
+ seg->log2_page_size = wr->wr.fast_reg.page_shift;
+}
+
+static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr)
+{
+ memset(seg, 0, sizeof(*seg));
+ if (wr->send_flags & MLX5_IB_SEND_UMR_UNREG) {
+ seg->status = 1 << 6;
+ return;
+ }
+
+ seg->flags = convert_access(wr->wr.fast_reg.access_flags);
+ seg->flags_pd = cpu_to_be32(to_mpd((struct ib_pd *)wr->wr.fast_reg.page_list)->pdn);
+ seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start);
+ seg->len = cpu_to_be64(wr->wr.fast_reg.length);
+ seg->log2_page_size = wr->wr.fast_reg.page_shift;
+ seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+}
+
+static void set_frwr_pages(struct mlx5_wqe_data_seg *dseg,
+ struct ib_send_wr *wr,
+ struct mlx5_core_dev *mdev,
+ struct mlx5_ib_pd *pd,
+ int writ)
+{
+ struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
+ u64 *page_list = wr->wr.fast_reg.page_list->page_list;
+ u64 perm = MLX5_EN_RD | (writ ? MLX5_EN_WR : 0);
+ int i;
+
+ for (i = 0; i < wr->wr.fast_reg.page_list_len; i++)
+ mfrpl->mapped_page_list[i] = cpu_to_be64(page_list[i] | perm);
+ dseg->addr = cpu_to_be64(mfrpl->map);
+ dseg->byte_count = cpu_to_be32(ALIGN(sizeof(u64) * wr->wr.fast_reg.page_list_len, 64));
+ dseg->lkey = cpu_to_be32(pd->pa_lkey);
+}
+
+static __be32 send_ieth(struct ib_send_wr *wr)
+{
+ switch (wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ return wr->ex.imm_data;
+
+ case IB_WR_SEND_WITH_INV:
+ return cpu_to_be32(wr->ex.invalidate_rkey);
+
+ default:
+ return 0;
+ }
+}
+
+static u8 calc_sig(void *wqe, int size)
+{
+ u8 *p = wqe;
+ u8 res = 0;
+ int i;
+
+ for (i = 0; i < size; i++)
+ res ^= p[i];
+
+ return ~res;
+}
+
+static u8 wq_sig(void *wqe)
+{
+ return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4);
+}
+
+static int set_data_inl_seg(struct mlx5_ib_qp *qp, struct ib_send_wr *wr,
+ void *wqe, int *sz)
+{
+ struct mlx5_wqe_inline_seg *seg;
+ void *qend = qp->sq.qend;
+ void *addr;
+ int inl = 0;
+ int copy;
+ int len;
+ int i;
+
+ seg = wqe;
+ wqe += sizeof(*seg);
+ for (i = 0; i < wr->num_sge; i++) {
+ addr = (void *)(unsigned long)(wr->sg_list[i].addr);
+ len = wr->sg_list[i].length;
+ inl += len;
+
+ if (unlikely(inl > qp->max_inline_data))
+ return -ENOMEM;
+
+ if (unlikely(wqe + len > qend)) {
+ copy = qend - wqe;
+ memcpy(wqe, addr, copy);
+ addr += copy;
+ len -= copy;
+ wqe = mlx5_get_send_wqe(qp, 0);
+ }
+ memcpy(wqe, addr, len);
+ wqe += len;
+ }
+
+ seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
+
+ *sz = ALIGN(inl + sizeof(seg->byte_count), 16) / 16;
+
+ return 0;
+}
+
+static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size,
+ struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp)
+{
+ int writ = 0;
+ int li;
+
+ li = wr->opcode == IB_WR_LOCAL_INV ? 1 : 0;
+ if (unlikely(wr->send_flags & IB_SEND_INLINE))
+ return -EINVAL;
+
+ set_frwr_umr_segment(*seg, wr, li);
+ *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+ *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+ set_mkey_segment(*seg, wr, li, &writ);
+ *seg += sizeof(struct mlx5_mkey_seg);
+ *size += sizeof(struct mlx5_mkey_seg) / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+ if (!li) {
+ set_frwr_pages(*seg, wr, mdev, pd, writ);
+ *seg += sizeof(struct mlx5_wqe_data_seg);
+ *size += (sizeof(struct mlx5_wqe_data_seg) / 16);
+ }
+ return 0;
+}
+
+static void dump_wqe(struct mlx5_ib_qp *qp, int idx, int size_16)
+{
+ __be32 *p = NULL;
+ int tidx = idx;
+ int i, j;
+
+ pr_debug("dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx));
+ for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
+ if ((i & 0xf) == 0) {
+ void *buf = mlx5_get_send_wqe(qp, tidx);
+ tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1);
+ p = buf;
+ j = 0;
+ }
+ pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]),
+ be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]),
+ be32_to_cpu(p[j + 3]));
+ }
+}
+
+static void mlx5_bf_copy(u64 __iomem *dst, u64 *src,
+ unsigned bytecnt, struct mlx5_ib_qp *qp)
+{
+ while (bytecnt > 0) {
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ __iowrite64_copy(dst++, src++, 8);
+ bytecnt -= 64;
+ if (unlikely(src == qp->sq.qend))
+ src = mlx5_get_send_wqe(qp, 0);
+ }
+}
+
+static u8 get_fence(u8 fence, struct ib_send_wr *wr)
+{
+ if (unlikely(wr->opcode == IB_WR_LOCAL_INV &&
+ wr->send_flags & IB_SEND_FENCE))
+ return MLX5_FENCE_MODE_STRONG_ORDERING;
+
+ if (unlikely(fence)) {
+ if (wr->send_flags & IB_SEND_FENCE)
+ return MLX5_FENCE_MODE_SMALL_AND_FENCE;
+ else
+ return fence;
+
+ } else {
+ return 0;
+ }
+}
+
+int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ struct mlx5_core_dev *mdev = &dev->mdev;
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ struct mlx5_wqe_data_seg *dpseg;
+ struct mlx5_wqe_xrc_seg *xrc;
+ struct mlx5_bf *bf = qp->bf;
+ int uninitialized_var(size);
+ void *qend = qp->sq.qend;
+ unsigned long flags;
+ u32 mlx5_opcode;
+ unsigned idx;
+ int err = 0;
+ int inl = 0;
+ int num_sge;
+ void *seg;
+ int nreq;
+ int i;
+ u8 next_fence = 0;
+ u8 opmod = 0;
+ u8 fence;
+
+ spin_lock_irqsave(&qp->sq.lock, flags);
+
+ for (nreq = 0; wr; nreq++, wr = wr->next) {
+ if (unlikely(wr->opcode >= sizeof(mlx5_ib_opcode) / sizeof(mlx5_ib_opcode[0]))) {
+ mlx5_ib_warn(dev, "\n");
+ err = -EINVAL;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) {
+ mlx5_ib_warn(dev, "\n");
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ fence = qp->fm_cache;
+ num_sge = wr->num_sge;
+ if (unlikely(num_sge > qp->sq.max_gs)) {
+ mlx5_ib_warn(dev, "\n");
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
+ seg = mlx5_get_send_wqe(qp, idx);
+ ctrl = seg;
+ *(uint32_t *)(seg + 8) = 0;
+ ctrl->imm = send_ieth(wr);
+ ctrl->fm_ce_se = qp->sq_signal_bits |
+ (wr->send_flags & IB_SEND_SIGNALED ?
+ MLX5_WQE_CTRL_CQ_UPDATE : 0) |
+ (wr->send_flags & IB_SEND_SOLICITED ?
+ MLX5_WQE_CTRL_SOLICITED : 0);
+
+ seg += sizeof(*ctrl);
+ size = sizeof(*ctrl) / 16;
+
+ switch (ibqp->qp_type) {
+ case IB_QPT_XRC_INI:
+ xrc = seg;
+ xrc->xrc_srqn = htonl(wr->xrc_remote_srq_num);
+ seg += sizeof(*xrc);
+ size += sizeof(*xrc) / 16;
+ /* fall through */
+ case IB_QPT_RC:
+ switch (wr->opcode) {
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ set_raddr_seg(seg, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ seg += sizeof(struct mlx5_wqe_raddr_seg);
+ size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
+ break;
+
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ set_raddr_seg(seg, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
+ seg += sizeof(struct mlx5_wqe_raddr_seg);
+
+ set_atomic_seg(seg, wr);
+ seg += sizeof(struct mlx5_wqe_atomic_seg);
+
+ size += (sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_atomic_seg)) / 16;
+ break;
+
+ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
+ set_raddr_seg(seg, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
+ seg += sizeof(struct mlx5_wqe_raddr_seg);
+
+ set_masked_atomic_seg(seg, wr);
+ seg += sizeof(struct mlx5_wqe_masked_atomic_seg);
+
+ size += (sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16;
+ break;
+
+ case IB_WR_LOCAL_INV:
+ next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+ qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
+ ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
+ err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+ num_sge = 0;
+ break;
+
+ case IB_WR_FAST_REG_MR:
+ next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+ qp->sq.wr_data[idx] = IB_WR_FAST_REG_MR;
+ ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
+ err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+ num_sge = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case IB_QPT_UC:
+ switch (wr->opcode) {
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ set_raddr_seg(seg, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ seg += sizeof(struct mlx5_wqe_raddr_seg);
+ size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ set_datagram_seg(seg, wr);
+ seg += sizeof(struct mlx5_wqe_datagram_seg);
+ size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
+ if (unlikely((seg == qend)))
+ seg = mlx5_get_send_wqe(qp, 0);
+ break;
+
+ case MLX5_IB_QPT_REG_UMR:
+ if (wr->opcode != MLX5_IB_WR_UMR) {
+ err = -EINVAL;
+ mlx5_ib_warn(dev, "bad opcode\n");
+ goto out;
+ }
+ qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
+ ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
+ set_reg_umr_segment(seg, wr);
+ seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+ size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+ if (unlikely((seg == qend)))
+ seg = mlx5_get_send_wqe(qp, 0);
+ set_reg_mkey_segment(seg, wr);
+ seg += sizeof(struct mlx5_mkey_seg);
+ size += sizeof(struct mlx5_mkey_seg) / 16;
+ if (unlikely((seg == qend)))
+ seg = mlx5_get_send_wqe(qp, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ if (wr->send_flags & IB_SEND_INLINE && num_sge) {
+ int uninitialized_var(sz);
+
+ err = set_data_inl_seg(qp, wr, seg, &sz);
+ if (unlikely(err)) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+ inl = 1;
+ size += sz;
+ } else {
+ dpseg = seg;
+ for (i = 0; i < num_sge; i++) {
+ if (unlikely(dpseg == qend)) {
+ seg = mlx5_get_send_wqe(qp, 0);
+ dpseg = seg;
+ }
+ if (likely(wr->sg_list[i].length)) {
+ set_data_ptr_seg(dpseg, wr->sg_list + i);
+ size += sizeof(struct mlx5_wqe_data_seg) / 16;
+ dpseg++;
+ }
+ }
+ }
+
+ mlx5_opcode = mlx5_ib_opcode[wr->opcode];
+ ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
+ mlx5_opcode |
+ ((u32)opmod << 24));
+ ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8));
+ ctrl->fm_ce_se |= get_fence(fence, wr);
+ qp->fm_cache = next_fence;
+ if (unlikely(qp->wq_sig))
+ ctrl->signature = wq_sig(ctrl);
+
+ qp->sq.wrid[idx] = wr->wr_id;
+ qp->sq.w_list[idx].opcode = mlx5_opcode;
+ qp->sq.wqe_head[idx] = qp->sq.head + nreq;
+ qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
+ qp->sq.w_list[idx].next = qp->sq.cur_post;
+
+ if (0)
+ dump_wqe(qp, idx, size);
+ }
+
+out:
+ if (likely(nreq)) {
+ qp->sq.head += nreq;
+
+ /* Make sure that descriptors are written before
+ * updating doorbell record and ringing the doorbell
+ */
+ wmb();
+
+ qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
+
+ if (bf->need_lock)
+ spin_lock(&bf->lock);
+
+ /* TBD enable WC */
+ if (0 && nreq == 1 && bf->uuarn && inl && size > 1 && size <= bf->buf_size / 16) {
+ mlx5_bf_copy(bf->reg + bf->offset, (u64 *)ctrl, ALIGN(size * 16, 64), qp);
+ /* wc_wmb(); */
+ } else {
+ mlx5_write64((__be32 *)ctrl, bf->regreg + bf->offset,
+ MLX5_GET_DOORBELL_LOCK(&bf->lock32));
+ /* Make sure doorbells don't leak out of SQ spinlock
+ * and reach the HCA out of order.
+ */
+ mmiowb();
+ }
+ bf->offset ^= bf->buf_size;
+ if (bf->need_lock)
+ spin_unlock(&bf->lock);
+ }
+
+ spin_unlock_irqrestore(&qp->sq.lock, flags);
+
+ return err;
+}
+
+static void set_sig_seg(struct mlx5_rwqe_sig *sig, int size)
+{
+ sig->signature = calc_sig(sig, size);
+}
+
+int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ struct mlx5_wqe_data_seg *scat;
+ struct mlx5_rwqe_sig *sig;
+ unsigned long flags;
+ int err = 0;
+ int nreq;
+ int ind;
+ int i;
+
+ spin_lock_irqsave(&qp->rq.lock, flags);
+
+ ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
+
+ for (nreq = 0; wr; nreq++, wr = wr->next) {
+ if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ if (unlikely(wr->num_sge > qp->rq.max_gs)) {
+ err = -EINVAL;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ scat = get_recv_wqe(qp, ind);
+ if (qp->wq_sig)
+ scat++;
+
+ for (i = 0; i < wr->num_sge; i++)
+ set_data_ptr_seg(scat + i, wr->sg_list + i);
+
+ if (i < qp->rq.max_gs) {
+ scat[i].byte_count = 0;
+ scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
+ scat[i].addr = 0;
+ }
+
+ if (qp->wq_sig) {
+ sig = (struct mlx5_rwqe_sig *)scat;
+ set_sig_seg(sig, (qp->rq.max_gs + 1) << 2);
+ }
+
+ qp->rq.wrid[ind] = wr->wr_id;
+
+ ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
+ }
+
+out:
+ if (likely(nreq)) {
+ qp->rq.head += nreq;
+
+ /* Make sure that descriptors are written before
+ * doorbell record.
+ */
+ wmb();
+
+ *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
+ }
+
+ spin_unlock_irqrestore(&qp->rq.lock, flags);
+
+ return err;
+}
+
+static inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state)
+{
+ switch (mlx5_state) {
+ case MLX5_QP_STATE_RST: return IB_QPS_RESET;
+ case MLX5_QP_STATE_INIT: return IB_QPS_INIT;
+ case MLX5_QP_STATE_RTR: return IB_QPS_RTR;
+ case MLX5_QP_STATE_RTS: return IB_QPS_RTS;
+ case MLX5_QP_STATE_SQ_DRAINING:
+ case MLX5_QP_STATE_SQD: return IB_QPS_SQD;
+ case MLX5_QP_STATE_SQER: return IB_QPS_SQE;
+ case MLX5_QP_STATE_ERR: return IB_QPS_ERR;
+ default: return -1;
+ }
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state)
+{
+ switch (mlx5_mig_state) {
+ case MLX5_QP_PM_ARMED: return IB_MIG_ARMED;
+ case MLX5_QP_PM_REARM: return IB_MIG_REARM;
+ case MLX5_QP_PM_MIGRATED: return IB_MIG_MIGRATED;
+ default: return -1;
+ }
+}
+
+static int to_ib_qp_access_flags(int mlx5_flags)
+{
+ int ib_flags = 0;
+
+ if (mlx5_flags & MLX5_QP_BIT_RRE)
+ ib_flags |= IB_ACCESS_REMOTE_READ;
+ if (mlx5_flags & MLX5_QP_BIT_RWE)
+ ib_flags |= IB_ACCESS_REMOTE_WRITE;
+ if (mlx5_flags & MLX5_QP_BIT_RAE)
+ ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+ return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr,
+ struct mlx5_qp_path *path)
+{
+ struct mlx5_core_dev *dev = &ibdev->mdev;
+
+ memset(ib_ah_attr, 0, sizeof(*ib_ah_attr));
+ ib_ah_attr->port_num = path->port;
+
+ if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
+ return;
+
+ ib_ah_attr->sl = path->sl & 0xf;
+
+ ib_ah_attr->dlid = be16_to_cpu(path->rlid);
+ ib_ah_attr->src_path_bits = path->grh_mlid & 0x7f;
+ ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0;
+ ib_ah_attr->ah_flags = (path->grh_mlid & (1 << 7)) ? IB_AH_GRH : 0;
+ if (ib_ah_attr->ah_flags) {
+ ib_ah_attr->grh.sgid_index = path->mgid_index;
+ ib_ah_attr->grh.hop_limit = path->hop_limit;
+ ib_ah_attr->grh.traffic_class =
+ (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
+ ib_ah_attr->grh.flow_label =
+ be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
+ memcpy(ib_ah_attr->grh.dgid.raw,
+ path->rgid, sizeof(ib_ah_attr->grh.dgid.raw));
+ }
+}
+
+int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ struct mlx5_query_qp_mbox_out *outb;
+ struct mlx5_qp_context *context;
+ int mlx5_state;
+ int err = 0;
+
+ mutex_lock(&qp->mutex);
+ outb = kzalloc(sizeof(*outb), GFP_KERNEL);
+ if (!outb) {
+ err = -ENOMEM;
+ goto out;
+ }
+ context = &outb->ctx;
+ err = mlx5_core_qp_query(&dev->mdev, &qp->mqp, outb, sizeof(*outb));
+ if (err)
+ goto out_free;
+
+ mlx5_state = be32_to_cpu(context->flags) >> 28;
+
+ qp->state = to_ib_qp_state(mlx5_state);
+ qp_attr->qp_state = qp->state;
+ qp_attr->path_mtu = context->mtu_msgmax >> 5;
+ qp_attr->path_mig_state =
+ to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+ qp_attr->qkey = be32_to_cpu(context->qkey);
+ qp_attr->rq_psn = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+ qp_attr->sq_psn = be32_to_cpu(context->next_send_psn) & 0xffffff;
+ qp_attr->dest_qp_num = be32_to_cpu(context->log_pg_sz_remote_qpn) & 0xffffff;
+ qp_attr->qp_access_flags =
+ to_ib_qp_access_flags(be32_to_cpu(context->params2));
+
+ if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
+ to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+ to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+ qp_attr->alt_pkey_index = context->alt_path.pkey_index & 0x7f;
+ qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
+ }
+
+ qp_attr->pkey_index = context->pri_path.pkey_index & 0x7f;
+ qp_attr->port_num = context->pri_path.port;
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+ qp_attr->sq_draining = mlx5_state == MLX5_QP_STATE_SQ_DRAINING;
+
+ qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+ qp_attr->max_dest_rd_atomic =
+ 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+ qp_attr->min_rnr_timer =
+ (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+ qp_attr->timeout = context->pri_path.ackto_lt >> 3;
+ qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7;
+ qp_attr->rnr_retry = (be32_to_cpu(context->params1) >> 13) & 0x7;
+ qp_attr->alt_timeout = context->alt_path.ackto_lt >> 3;
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt;
+ qp_attr->cap.max_recv_sge = qp->rq.max_gs;
+
+ if (!ibqp->uobject) {
+ qp_attr->cap.max_send_wr = qp->sq.wqe_cnt;
+ qp_attr->cap.max_send_sge = qp->sq.max_gs;
+ } else {
+ qp_attr->cap.max_send_wr = 0;
+ qp_attr->cap.max_send_sge = 0;
+ }
+
+ /* We don't support inline sends for kernel QPs (yet), and we
+ * don't know what userspace's value should be.
+ */
+ qp_attr->cap.max_inline_data = 0;
+
+ qp_init_attr->cap = qp_attr->cap;
+
+ qp_init_attr->create_flags = 0;
+ if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK)
+ qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
+
+ qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ?
+ IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
+
+out_free:
+ kfree(outb);
+
+out:
+ mutex_unlock(&qp->mutex);
+ return err;
+}
+
+struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_ib_xrcd *xrcd;
+ int err;
+
+ if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC))
+ return ERR_PTR(-ENOSYS);
+
+ xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL);
+ if (!xrcd)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx5_core_xrcd_alloc(&dev->mdev, &xrcd->xrcdn);
+ if (err) {
+ kfree(xrcd);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return &xrcd->ibxrcd;
+}
+
+int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
+{
+ struct mlx5_ib_dev *dev = to_mdev(xrcd->device);
+ u32 xrcdn = to_mxrcd(xrcd)->xrcdn;
+ int err;
+
+ err = mlx5_core_xrcd_dealloc(&dev->mdev, xrcdn);
+ if (err) {
+ mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn);
+ return err;
+ }
+
+ kfree(xrcd);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
new file mode 100644
index 000000000000..84d297afd6a9
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/slab.h>
+#include <rdma/ib_umem.h>
+
+#include "mlx5_ib.h"
+#include "user.h"
+
+/* not supported currently */
+static int srq_signature;
+
+static void *get_wqe(struct mlx5_ib_srq *srq, int n)
+{
+ return mlx5_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
+}
+
+static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
+{
+ struct ib_event event;
+ struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
+
+ if (ibsrq->event_handler) {
+ event.device = ibsrq->device;
+ event.element.srq = ibsrq;
+ switch (type) {
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ event.event = IB_EVENT_SRQ_LIMIT_REACHED;
+ break;
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ event.event = IB_EVENT_SRQ_ERR;
+ break;
+ default:
+ pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n",
+ type, srq->srqn);
+ return;
+ }
+
+ ibsrq->event_handler(&event, ibsrq->srq_context);
+ }
+}
+
+static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
+ struct mlx5_create_srq_mbox_in **in,
+ struct ib_udata *udata, int buf_size, int *inlen)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_ib_create_srq ucmd;
+ int err;
+ int npages;
+ int page_shift;
+ int ncont;
+ u32 offset;
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+ mlx5_ib_dbg(dev, "failed copy udata\n");
+ return -EFAULT;
+ }
+ srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
+
+ srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,
+ 0, 0);
+ if (IS_ERR(srq->umem)) {
+ mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size);
+ err = PTR_ERR(srq->umem);
+ return err;
+ }
+
+ mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, &npages,
+ &page_shift, &ncont, NULL);
+ err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift,
+ &offset);
+ if (err) {
+ mlx5_ib_warn(dev, "bad offset\n");
+ goto err_umem;
+ }
+
+ *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
+ *in = mlx5_vzalloc(*inlen);
+ if (!(*in)) {
+ err = -ENOMEM;
+ goto err_umem;
+ }
+
+ mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0);
+
+ err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context),
+ ucmd.db_addr, &srq->db);
+ if (err) {
+ mlx5_ib_dbg(dev, "map doorbell failed\n");
+ goto err_in;
+ }
+
+ (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+ (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
+
+ return 0;
+
+err_in:
+ mlx5_vfree(*in);
+
+err_umem:
+ ib_umem_release(srq->umem);
+
+ return err;
+}
+
+static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
+ struct mlx5_create_srq_mbox_in **in, int buf_size,
+ int *inlen)
+{
+ int err;
+ int i;
+ struct mlx5_wqe_srq_next_seg *next;
+ int page_shift;
+ int npages;
+
+ err = mlx5_db_alloc(&dev->mdev, &srq->db);
+ if (err) {
+ mlx5_ib_warn(dev, "alloc dbell rec failed\n");
+ return err;
+ }
+
+ *srq->db.db = 0;
+
+ if (mlx5_buf_alloc(&dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
+ mlx5_ib_dbg(dev, "buf alloc failed\n");
+ err = -ENOMEM;
+ goto err_db;
+ }
+ page_shift = srq->buf.page_shift;
+
+ srq->head = 0;
+ srq->tail = srq->msrq.max - 1;
+ srq->wqe_ctr = 0;
+
+ for (i = 0; i < srq->msrq.max; i++) {
+ next = get_wqe(srq, i);
+ next->next_wqe_index =
+ cpu_to_be16((i + 1) & (srq->msrq.max - 1));
+ }
+
+ npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT));
+ mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n",
+ buf_size, page_shift, srq->buf.npages, npages);
+ *inlen = sizeof(**in) + sizeof(*(*in)->pas) * npages;
+ *in = mlx5_vzalloc(*inlen);
+ if (!*in) {
+ err = -ENOMEM;
+ goto err_buf;
+ }
+ mlx5_fill_page_array(&srq->buf, (*in)->pas);
+
+ srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL);
+ if (!srq->wrid) {
+ mlx5_ib_dbg(dev, "kmalloc failed %lu\n",
+ (unsigned long)(srq->msrq.max * sizeof(u64)));
+ err = -ENOMEM;
+ goto err_in;
+ }
+ srq->wq_sig = !!srq_signature;
+
+ (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+
+ return 0;
+
+err_in:
+ mlx5_vfree(*in);
+
+err_buf:
+ mlx5_buf_free(&dev->mdev, &srq->buf);
+
+err_db:
+ mlx5_db_free(&dev->mdev, &srq->db);
+ return err;
+}
+
+static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq)
+{
+ mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
+ ib_umem_release(srq->umem);
+}
+
+
+static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq)
+{
+ kfree(srq->wrid);
+ mlx5_buf_free(&dev->mdev, &srq->buf);
+ mlx5_db_free(&dev->mdev, &srq->db);
+}
+
+struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_ib_srq *srq;
+ int desc_size;
+ int buf_size;
+ int err;
+ struct mlx5_create_srq_mbox_in *uninitialized_var(in);
+ int uninitialized_var(inlen);
+ int is_xrc;
+ u32 flgs, xrcdn;
+
+ /* Sanity check SRQ size before proceeding */
+ if (init_attr->attr.max_wr >= dev->mdev.caps.max_srq_wqes) {
+ mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
+ init_attr->attr.max_wr,
+ dev->mdev.caps.max_srq_wqes);
+ return ERR_PTR(-EINVAL);
+ }
+
+ srq = kmalloc(sizeof(*srq), GFP_KERNEL);
+ if (!srq)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&srq->mutex);
+ spin_lock_init(&srq->lock);
+ srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1);
+ srq->msrq.max_gs = init_attr->attr.max_sge;
+
+ desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
+ srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
+ desc_size = roundup_pow_of_two(desc_size);
+ desc_size = max_t(int, 32, desc_size);
+ srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
+ sizeof(struct mlx5_wqe_data_seg);
+ srq->msrq.wqe_shift = ilog2(desc_size);
+ buf_size = srq->msrq.max * desc_size;
+ mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n",
+ desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
+ srq->msrq.max_avail_gather);
+
+ if (pd->uobject)
+ err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen);
+ else
+ err = create_srq_kernel(dev, srq, &in, buf_size, &inlen);
+
+ if (err) {
+ mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
+ pd->uobject ? "user" : "kernel", err);
+ goto err_srq;
+ }
+
+ is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
+ in->ctx.state_log_sz = ilog2(srq->msrq.max);
+ flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24;
+ xrcdn = 0;
+ if (is_xrc) {
+ xrcdn = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
+ in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(init_attr->ext.xrc.cq)->mcq.cqn);
+ } else if (init_attr->srq_type == IB_SRQT_BASIC) {
+ xrcdn = to_mxrcd(dev->devr.x0)->xrcdn;
+ in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(dev->devr.c0)->mcq.cqn);
+ }
+
+ in->ctx.flags_xrcd = cpu_to_be32((flgs & 0xFF000000) | (xrcdn & 0xFFFFFF));
+
+ in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn);
+ in->ctx.db_record = cpu_to_be64(srq->db.dma);
+ err = mlx5_core_create_srq(&dev->mdev, &srq->msrq, in, inlen);
+ mlx5_vfree(in);
+ if (err) {
+ mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
+ goto err_srq;
+ }
+
+ mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
+
+ srq->msrq.event = mlx5_ib_srq_event;
+ srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
+
+ if (pd->uobject)
+ if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
+ mlx5_ib_dbg(dev, "copy to user failed\n");
+ err = -EFAULT;
+ goto err_core;
+ }
+
+ init_attr->attr.max_wr = srq->msrq.max - 1;
+
+ return &srq->ibsrq;
+
+err_core:
+ mlx5_core_destroy_srq(&dev->mdev, &srq->msrq);
+ if (pd->uobject)
+ destroy_srq_user(pd, srq);
+ else
+ destroy_srq_kernel(dev, srq);
+
+err_srq:
+ kfree(srq);
+
+ return ERR_PTR(err);
+}
+
+int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
+ struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+ int ret;
+
+ /* We don't support resizing SRQs yet */
+ if (attr_mask & IB_SRQ_MAX_WR)
+ return -EINVAL;
+
+ if (attr_mask & IB_SRQ_LIMIT) {
+ if (attr->srq_limit >= srq->msrq.max)
+ return -EINVAL;
+
+ mutex_lock(&srq->mutex);
+ ret = mlx5_core_arm_srq(&dev->mdev, &srq->msrq, attr->srq_limit, 1);
+ mutex_unlock(&srq->mutex);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
+ struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+ int ret;
+ struct mlx5_query_srq_mbox_out *out;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ ret = mlx5_core_query_srq(&dev->mdev, &srq->msrq, out);
+ if (ret)
+ goto out_box;
+
+ srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm);
+ srq_attr->max_wr = srq->msrq.max - 1;
+ srq_attr->max_sge = srq->msrq.max_gs;
+
+out_box:
+ kfree(out);
+ return ret;
+}
+
+int mlx5_ib_destroy_srq(struct ib_srq *srq)
+{
+ struct mlx5_ib_dev *dev = to_mdev(srq->device);
+ struct mlx5_ib_srq *msrq = to_msrq(srq);
+
+ mlx5_core_destroy_srq(&dev->mdev, &msrq->msrq);
+
+ if (srq->uobject) {
+ mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
+ ib_umem_release(msrq->umem);
+ } else {
+ kfree(msrq->wrid);
+ mlx5_buf_free(&dev->mdev, &msrq->buf);
+ mlx5_db_free(&dev->mdev, &msrq->db);
+ }
+
+ kfree(srq);
+ return 0;
+}
+
+void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index)
+{
+ struct mlx5_wqe_srq_next_seg *next;
+
+ /* always called with interrupts disabled. */
+ spin_lock(&srq->lock);
+
+ next = get_wqe(srq, srq->tail);
+ next->next_wqe_index = cpu_to_be16(wqe_index);
+ srq->tail = wqe_index;
+
+ spin_unlock(&srq->lock);
+}
+
+int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+ struct mlx5_wqe_srq_next_seg *next;
+ struct mlx5_wqe_data_seg *scat;
+ unsigned long flags;
+ int err = 0;
+ int nreq;
+ int i;
+
+ spin_lock_irqsave(&srq->lock, flags);
+
+ for (nreq = 0; wr; nreq++, wr = wr->next) {
+ if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
+ err = -EINVAL;
+ *bad_wr = wr;
+ break;
+ }
+
+ if (unlikely(srq->head == srq->tail)) {
+ err = -ENOMEM;
+ *bad_wr = wr;
+ break;
+ }
+
+ srq->wrid[srq->head] = wr->wr_id;
+
+ next = get_wqe(srq, srq->head);
+ srq->head = be16_to_cpu(next->next_wqe_index);
+ scat = (struct mlx5_wqe_data_seg *)(next + 1);
+
+ for (i = 0; i < wr->num_sge; i++) {
+ scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
+ scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey);
+ scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
+ }
+
+ if (i < srq->msrq.max_avail_gather) {
+ scat[i].byte_count = 0;
+ scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
+ scat[i].addr = 0;
+ }
+ }
+
+ if (likely(nreq)) {
+ srq->wqe_ctr += nreq;
+
+ /* Make sure that descriptors are written before
+ * doorbell record.
+ */
+ wmb();
+
+ *srq->db.db = cpu_to_be32(srq->wqe_ctr);
+ }
+
+ spin_unlock_irqrestore(&srq->lock, flags);
+
+ return err;
+}
diff --git a/drivers/infiniband/hw/mlx5/user.h b/drivers/infiniband/hw/mlx5/user.h
new file mode 100644
index 000000000000..a886de3e593c
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/user.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_IB_USER_H
+#define MLX5_IB_USER_H
+
+#include <linux/types.h>
+
+enum {
+ MLX5_QP_FLAG_SIGNATURE = 1 << 0,
+ MLX5_QP_FLAG_SCATTER_CQE = 1 << 1,
+};
+
+enum {
+ MLX5_SRQ_FLAG_SIGNATURE = 1 << 0,
+};
+
+
+/* Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define MLX5_IB_UVERBS_ABI_VERSION 1
+
+/* Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mlx5_ib_alloc_ucontext_req {
+ __u32 total_num_uuars;
+ __u32 num_low_latency_uuars;
+};
+
+struct mlx5_ib_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+ __u32 bf_reg_size;
+ __u32 tot_uuars;
+ __u32 cache_line_size;
+ __u16 max_sq_desc_sz;
+ __u16 max_rq_desc_sz;
+ __u32 max_send_wqebb;
+ __u32 max_recv_wr;
+ __u32 max_srq_recv_wr;
+ __u16 num_ports;
+ __u16 reserved;
+};
+
+struct mlx5_ib_alloc_pd_resp {
+ __u32 pdn;
+};
+
+struct mlx5_ib_create_cq {
+ __u64 buf_addr;
+ __u64 db_addr;
+ __u32 cqe_size;
+};
+
+struct mlx5_ib_create_cq_resp {
+ __u32 cqn;
+ __u32 reserved;
+};
+
+struct mlx5_ib_resize_cq {
+ __u64 buf_addr;
+};
+
+struct mlx5_ib_create_srq {
+ __u64 buf_addr;
+ __u64 db_addr;
+ __u32 flags;
+};
+
+struct mlx5_ib_create_srq_resp {
+ __u32 srqn;
+ __u32 reserved;
+};
+
+struct mlx5_ib_create_qp {
+ __u64 buf_addr;
+ __u64 db_addr;
+ __u32 sq_wqe_count;
+ __u32 rq_wqe_count;
+ __u32 rq_wqe_shift;
+ __u32 flags;
+};
+
+struct mlx5_ib_create_qp_resp {
+ __u32 uuar_index;
+};
+#endif /* MLX5_IB_USER_H */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index 48970af23679..d540180a8e42 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -42,8 +42,6 @@
#define OCRDMA_ROCE_DEV_VERSION "1.0.0"
#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
-#define ocrdma_err(format, arg...) printk(KERN_ERR format, ##arg)
-
#define OCRDMA_MAX_AH 512
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
@@ -97,7 +95,6 @@ struct ocrdma_queue_info {
u16 id; /* qid, where to ring the doorbell. */
u16 head, tail;
bool created;
- atomic_t used; /* Number of valid elements in the queue */
};
struct ocrdma_eq {
@@ -198,7 +195,6 @@ struct ocrdma_cq {
struct ocrdma_ucontext *ucontext;
dma_addr_t pa;
u32 len;
- atomic_t use_cnt;
/* head of all qp's sq and rq for which cqes need to be flushed
* by the software.
@@ -210,7 +206,6 @@ struct ocrdma_pd {
struct ib_pd ibpd;
struct ocrdma_dev *dev;
struct ocrdma_ucontext *uctx;
- atomic_t use_cnt;
u32 id;
int num_dpp_qp;
u32 dpp_page;
@@ -241,16 +236,16 @@ struct ocrdma_srq {
struct ib_srq ibsrq;
struct ocrdma_dev *dev;
u8 __iomem *db;
+ struct ocrdma_qp_hwq_info rq;
+ u64 *rqe_wr_id_tbl;
+ u32 *idx_bit_fields;
+ u32 bit_fields_len;
+
/* provide synchronization to multiple context(s) posting rqe */
spinlock_t q_lock ____cacheline_aligned;
- struct ocrdma_qp_hwq_info rq;
struct ocrdma_pd *pd;
- atomic_t use_cnt;
u32 id;
- u64 *rqe_wr_id_tbl;
- u32 *idx_bit_fields;
- u32 bit_fields_len;
};
struct ocrdma_qp {
@@ -258,8 +253,6 @@ struct ocrdma_qp {
struct ocrdma_dev *dev;
u8 __iomem *sq_db;
- /* provide synchronization to multiple context(s) posting wqe, rqe */
- spinlock_t q_lock ____cacheline_aligned;
struct ocrdma_qp_hwq_info sq;
struct {
uint64_t wrid;
@@ -269,6 +262,9 @@ struct ocrdma_qp {
uint8_t rsvd[3];
} *wqe_wr_id_tbl;
u32 max_inline_data;
+
+ /* provide synchronization to multiple context(s) posting wqe, rqe */
+ spinlock_t q_lock ____cacheline_aligned;
struct ocrdma_cq *sq_cq;
/* list maintained per CQ to flush SQ errors */
struct list_head sq_entry;
@@ -296,10 +292,6 @@ struct ocrdma_qp {
u8 *ird_q_va;
};
-#define OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp) \
- (((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) && \
- (qp->id < 64)) ? 24 : 16)
-
struct ocrdma_hw_mr {
struct ocrdma_dev *dev;
u32 lkey;
@@ -390,4 +382,43 @@ static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)
return container_of(ibsrq, struct ocrdma_srq, ibsrq);
}
+
+static inline int ocrdma_get_num_posted_shift(struct ocrdma_qp *qp)
+{
+ return ((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY &&
+ qp->id < 64) ? 24 : 16);
+}
+
+static inline int is_cqe_valid(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe)
+{
+ int cqe_valid;
+ cqe_valid = le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_VALID;
+ return ((cqe_valid == cq->phase) ? 1 : 0);
+}
+
+static inline int is_cqe_for_sq(struct ocrdma_cqe *cqe)
+{
+ return (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_QTYPE) ? 0 : 1;
+}
+
+static inline int is_cqe_invalidated(struct ocrdma_cqe *cqe)
+{
+ return (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_INVALIDATE) ? 1 : 0;
+}
+
+static inline int is_cqe_imm(struct ocrdma_cqe *cqe)
+{
+ return (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_IMM) ? 1 : 0;
+}
+
+static inline int is_cqe_wr_imm(struct ocrdma_cqe *cqe)
+{
+ return (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_WRITE_IMM) ? 1 : 0;
+}
+
+
#endif
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 71942af4fce9..0965278dd2ed 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -128,7 +128,6 @@ static inline struct ocrdma_mqe *ocrdma_get_mqe(struct ocrdma_dev *dev)
static inline void ocrdma_mq_inc_head(struct ocrdma_dev *dev)
{
dev->mq.sq.head = (dev->mq.sq.head + 1) & (OCRDMA_MQ_LEN - 1);
- atomic_inc(&dev->mq.sq.used);
}
static inline void *ocrdma_get_mqe_rsp(struct ocrdma_dev *dev)
@@ -564,32 +563,19 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
memset(cmd, 0, sizeof(*cmd));
num_pages = PAGES_4K_SPANNED(mq->va, mq->size);
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
- ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ,
- OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
- cmd->v0.pages = num_pages;
- cmd->v0.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
- cmd->v0.async_cqid_valid = (cq->id << 1);
- cmd->v0.cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
- OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
- cmd->v0.cqid_ringsize |=
- (cq->id << OCRDMA_CREATE_MQ_V0_CQ_ID_SHIFT);
- cmd->v0.valid = OCRDMA_CREATE_MQ_VALID;
- pa = &cmd->v0.pa[0];
- } else {
- ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,
- OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
- cmd->req.rsvd_version = 1;
- cmd->v1.cqid_pages = num_pages;
- cmd->v1.cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);
- cmd->v1.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
- cmd->v1.async_event_bitmap = Bit(20);
- cmd->v1.async_cqid_ringsize = cq->id;
- cmd->v1.async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
- OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
- cmd->v1.valid = OCRDMA_CREATE_MQ_VALID;
- pa = &cmd->v1.pa[0];
- }
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ cmd->req.rsvd_version = 1;
+ cmd->cqid_pages = num_pages;
+ cmd->cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);
+ cmd->async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
+ cmd->async_event_bitmap = Bit(20);
+ cmd->async_cqid_ringsize = cq->id;
+ cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
+ cmd->valid = OCRDMA_CREATE_MQ_VALID;
+ pa = &cmd->pa[0];
+
ocrdma_build_q_pages(pa, num_pages, mq->dma, PAGE_SIZE_4K);
status = be_roce_mcc_cmd(dev->nic_info.netdev,
cmd, sizeof(*cmd), NULL, NULL);
@@ -745,7 +731,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
qp_event = 0;
srq_event = 0;
dev_event = 0;
- ocrdma_err("%s() unknown type=0x%x\n", __func__, type);
+ pr_err("%s() unknown type=0x%x\n", __func__, type);
break;
}
@@ -775,8 +761,8 @@ static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
if (evt_code == OCRDMA_ASYNC_EVE_CODE)
ocrdma_dispatch_ibevent(dev, cqe);
else
- ocrdma_err("%s(%d) invalid evt code=0x%x\n",
- __func__, dev->id, evt_code);
+ pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
+ dev->id, evt_code);
}
static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -790,8 +776,8 @@ static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
dev->mqe_ctx.cmd_done = true;
wake_up(&dev->mqe_ctx.cmd_wait);
} else
- ocrdma_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",
- __func__, cqe->tag_lo, dev->mqe_ctx.tag);
+ pr_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",
+ __func__, cqe->tag_lo, dev->mqe_ctx.tag);
}
static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
@@ -810,7 +796,7 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
else if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_CMPL_MASK)
ocrdma_process_mcqe(dev, cqe);
else
- ocrdma_err("%s() cqe->compl is not set.\n", __func__);
+ pr_err("%s() cqe->compl is not set.\n", __func__);
memset(cqe, 0, sizeof(struct ocrdma_mcqe));
ocrdma_mcq_inc_tail(dev);
}
@@ -869,7 +855,7 @@ static void ocrdma_qp_cq_handler(struct ocrdma_dev *dev, u16 cq_idx)
cq = dev->cq_tbl[cq_idx];
if (cq == NULL) {
- ocrdma_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
+ pr_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
return;
}
spin_lock_irqsave(&cq->cq_lock, flags);
@@ -971,7 +957,7 @@ static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)
rsp = ocrdma_get_mqe_rsp(dev);
ocrdma_copy_le32_to_cpu(mqe, rsp, (sizeof(*mqe)));
if (cqe_status || ext_status) {
- ocrdma_err
+ pr_err
("%s() opcode=0x%x, cqe_status=0x%x, ext_status=0x%x\n",
__func__,
(rsp->u.rsp.subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
@@ -1353,8 +1339,8 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
if (dpp_cq)
return -EINVAL;
if (entries > dev->attr.max_cqe) {
- ocrdma_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",
- __func__, dev->id, dev->attr.max_cqe, entries);
+ pr_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",
+ __func__, dev->id, dev->attr.max_cqe, entries);
return -EINVAL;
}
if (dpp_cq && (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY))
@@ -1621,7 +1607,7 @@ int ocrdma_reg_mr(struct ocrdma_dev *dev,
status = ocrdma_mbx_reg_mr(dev, hwmr, pdid,
cur_pbl_cnt, hwmr->pbe_size, last);
if (status) {
- ocrdma_err("%s() status=%d\n", __func__, status);
+ pr_err("%s() status=%d\n", __func__, status);
return status;
}
/* if there is no more pbls to register then exit. */
@@ -1644,7 +1630,7 @@ int ocrdma_reg_mr(struct ocrdma_dev *dev,
break;
}
if (status)
- ocrdma_err("%s() err. status=%d\n", __func__, status);
+ pr_err("%s() err. status=%d\n", __func__, status);
return status;
}
@@ -1841,8 +1827,8 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
status = ocrdma_build_q_conf(&max_wqe_allocated,
dev->attr.wqe_size, &hw_pages, &hw_page_size);
if (status) {
- ocrdma_err("%s() req. max_send_wr=0x%x\n", __func__,
- max_wqe_allocated);
+ pr_err("%s() req. max_send_wr=0x%x\n", __func__,
+ max_wqe_allocated);
return -EINVAL;
}
qp->sq.max_cnt = max_wqe_allocated;
@@ -1891,8 +1877,8 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
status = ocrdma_build_q_conf(&max_rqe_allocated, dev->attr.rqe_size,
&hw_pages, &hw_page_size);
if (status) {
- ocrdma_err("%s() req. max_recv_wr=0x%x\n", __func__,
- attrs->cap.max_recv_wr + 1);
+ pr_err("%s() req. max_recv_wr=0x%x\n", __func__,
+ attrs->cap.max_recv_wr + 1);
return status;
}
qp->rq.max_cnt = max_rqe_allocated;
@@ -1900,7 +1886,7 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
qp->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);
if (!qp->rq.va)
- return status;
+ return -ENOMEM;
memset(qp->rq.va, 0, len);
qp->rq.pa = pa;
qp->rq.len = len;
@@ -2087,10 +2073,10 @@ mbx_err:
if (qp->rq.va)
dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);
rq_err:
- ocrdma_err("%s(%d) rq_err\n", __func__, dev->id);
+ pr_err("%s(%d) rq_err\n", __func__, dev->id);
dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);
sq_err:
- ocrdma_err("%s(%d) sq_err\n", __func__, dev->id);
+ pr_err("%s(%d) sq_err\n", __func__, dev->id);
kfree(cmd);
return status;
}
@@ -2127,7 +2113,7 @@ int ocrdma_resolve_dgid(struct ocrdma_dev *dev, union ib_gid *dgid,
else if (rdma_link_local_addr(&in6))
rdma_get_ll_mac(&in6, mac_addr);
else {
- ocrdma_err("%s() fail to resolve mac_addr.\n", __func__);
+ pr_err("%s() fail to resolve mac_addr.\n", __func__);
return -EINVAL;
}
return 0;
@@ -2362,8 +2348,8 @@ int ocrdma_mbx_create_srq(struct ocrdma_srq *srq,
dev->attr.rqe_size,
&hw_pages, &hw_page_size);
if (status) {
- ocrdma_err("%s() req. max_wr=0x%x\n", __func__,
- srq_attr->attr.max_wr);
+ pr_err("%s() req. max_wr=0x%x\n", __func__,
+ srq_attr->attr.max_wr);
status = -EINVAL;
goto ret;
}
@@ -2614,7 +2600,7 @@ mq_err:
ocrdma_destroy_qp_eqs(dev);
qpeq_err:
ocrdma_destroy_eq(dev, &dev->meq);
- ocrdma_err("%s() status=%d\n", __func__, status);
+ pr_err("%s() status=%d\n", __func__, status);
return status;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 48928c8e7774..ded416f1adea 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -378,7 +378,7 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
spin_lock_init(&dev->flush_q_lock);
return 0;
alloc_err:
- ocrdma_err("%s(%d) error.\n", __func__, dev->id);
+ pr_err("%s(%d) error.\n", __func__, dev->id);
return -ENOMEM;
}
@@ -396,7 +396,7 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
if (!dev) {
- ocrdma_err("Unable to allocate ib device\n");
+ pr_err("Unable to allocate ib device\n");
return NULL;
}
dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL);
@@ -437,7 +437,7 @@ init_err:
idr_err:
kfree(dev->mbx_cmd);
ib_dealloc_device(&dev->ibdev);
- ocrdma_err("%s() leaving. ret=%d\n", __func__, status);
+ pr_err("%s() leaving. ret=%d\n", __func__, status);
return NULL;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index c75cbdfa87e7..36b062da2aea 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -608,16 +608,8 @@ enum {
OCRDMA_CREATE_MQ_ASYNC_CQ_VALID = Bit(0)
};
-struct ocrdma_create_mq_v0 {
- u32 pages;
- u32 cqid_ringsize;
- u32 valid;
- u32 async_cqid_valid;
- u32 rsvd;
- struct ocrdma_pa pa[8];
-} __packed;
-
-struct ocrdma_create_mq_v1 {
+struct ocrdma_create_mq_req {
+ struct ocrdma_mbx_hdr req;
u32 cqid_pages;
u32 async_event_bitmap;
u32 async_cqid_ringsize;
@@ -627,14 +619,6 @@ struct ocrdma_create_mq_v1 {
struct ocrdma_pa pa[8];
} __packed;
-struct ocrdma_create_mq_req {
- struct ocrdma_mbx_hdr req;
- union {
- struct ocrdma_create_mq_v0 v0;
- struct ocrdma_create_mq_v1 v1;
- };
-} __packed;
-
struct ocrdma_create_mq_rsp {
struct ocrdma_mbx_rsp rsp;
u32 id;
@@ -1550,21 +1534,6 @@ struct ocrdma_cqe {
u32 flags_status_srcqpn; /* w3 */
} __packed;
-#define is_cqe_valid(cq, cqe) \
- (((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_VALID)\
- == cq->phase) ? 1 : 0)
-#define is_cqe_for_sq(cqe) \
- ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 0 : 1)
-#define is_cqe_for_rq(cqe) \
- ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 1 : 0)
-#define is_cqe_invalidated(cqe) \
- ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_INVALIDATE) ? \
- 1 : 0)
-#define is_cqe_imm(cqe) \
- ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_IMM) ? 1 : 0)
-#define is_cqe_wr_imm(cqe) \
- ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_WRITE_IMM) ? 1 : 0)
-
struct ocrdma_sge {
u32 addr_hi;
u32 addr_lo;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index b29a4246ef41..dcfbab177faa 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -114,8 +114,8 @@ int ocrdma_query_port(struct ib_device *ibdev,
dev = get_ocrdma_dev(ibdev);
if (port > 1) {
- ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
- dev->id, port);
+ pr_err("%s(%d) invalid_port=0x%x\n", __func__,
+ dev->id, port);
return -EINVAL;
}
netdev = dev->nic_info.netdev;
@@ -155,8 +155,7 @@ int ocrdma_modify_port(struct ib_device *ibdev, u8 port, int mask,
dev = get_ocrdma_dev(ibdev);
if (port > 1) {
- ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
- dev->id, port);
+ pr_err("%s(%d) invalid_port=0x%x\n", __func__, dev->id, port);
return -EINVAL;
}
return 0;
@@ -398,7 +397,6 @@ struct ib_pd *ocrdma_alloc_pd(struct ib_device *ibdev,
kfree(pd);
return ERR_PTR(status);
}
- atomic_set(&pd->use_cnt, 0);
if (udata && context) {
status = ocrdma_copy_pd_uresp(pd, context, udata);
@@ -419,12 +417,6 @@ int ocrdma_dealloc_pd(struct ib_pd *ibpd)
int status;
u64 usr_db;
- if (atomic_read(&pd->use_cnt)) {
- ocrdma_err("%s(%d) pd=0x%x is in use.\n",
- __func__, dev->id, pd->id);
- status = -EFAULT;
- goto dealloc_err;
- }
status = ocrdma_mbx_dealloc_pd(dev, pd);
if (pd->uctx) {
u64 dpp_db = dev->nic_info.dpp_unmapped_addr +
@@ -436,7 +428,6 @@ int ocrdma_dealloc_pd(struct ib_pd *ibpd)
ocrdma_del_mmap(pd->uctx, usr_db, dev->nic_info.db_page_size);
}
kfree(pd);
-dealloc_err:
return status;
}
@@ -450,8 +441,8 @@ static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,
struct ocrdma_dev *dev = pd->dev;
if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) {
- ocrdma_err("%s(%d) leaving err, invalid access rights\n",
- __func__, dev->id);
+ pr_err("%s(%d) leaving err, invalid access rights\n",
+ __func__, dev->id);
return ERR_PTR(-EINVAL);
}
@@ -474,7 +465,6 @@ static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,
return ERR_PTR(-ENOMEM);
}
mr->pd = pd;
- atomic_inc(&pd->use_cnt);
mr->ibmr.lkey = mr->hwmr.lkey;
if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
mr->ibmr.rkey = mr->hwmr.lkey;
@@ -664,7 +654,6 @@ struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len,
if (status)
goto mbx_err;
mr->pd = pd;
- atomic_inc(&pd->use_cnt);
mr->ibmr.lkey = mr->hwmr.lkey;
if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
mr->ibmr.rkey = mr->hwmr.lkey;
@@ -689,7 +678,6 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
if (mr->hwmr.fr_mr == 0)
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
- atomic_dec(&mr->pd->use_cnt);
/* it could be user registered memory. */
if (mr->umem)
ib_umem_release(mr->umem);
@@ -714,8 +702,8 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
uresp.phase_change = cq->phase_change ? 1 : 0;
status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
if (status) {
- ocrdma_err("%s(%d) copy error cqid=0x%x.\n",
- __func__, cq->dev->id, cq->id);
+ pr_err("%s(%d) copy error cqid=0x%x.\n",
+ __func__, cq->dev->id, cq->id);
goto err;
}
uctx = get_ocrdma_ucontext(ib_ctx);
@@ -752,7 +740,6 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
spin_lock_init(&cq->cq_lock);
spin_lock_init(&cq->comp_handler_lock);
- atomic_set(&cq->use_cnt, 0);
INIT_LIST_HEAD(&cq->sq_head);
INIT_LIST_HEAD(&cq->rq_head);
cq->dev = dev;
@@ -799,9 +786,6 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_dev *dev = cq->dev;
- if (atomic_read(&cq->use_cnt))
- return -EINVAL;
-
status = ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
@@ -837,57 +821,56 @@ static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,
if (attrs->qp_type != IB_QPT_GSI &&
attrs->qp_type != IB_QPT_RC &&
attrs->qp_type != IB_QPT_UD) {
- ocrdma_err("%s(%d) unsupported qp type=0x%x requested\n",
- __func__, dev->id, attrs->qp_type);
+ pr_err("%s(%d) unsupported qp type=0x%x requested\n",
+ __func__, dev->id, attrs->qp_type);
return -EINVAL;
}
if (attrs->cap.max_send_wr > dev->attr.max_wqe) {
- ocrdma_err("%s(%d) unsupported send_wr=0x%x requested\n",
- __func__, dev->id, attrs->cap.max_send_wr);
- ocrdma_err("%s(%d) supported send_wr=0x%x\n",
- __func__, dev->id, dev->attr.max_wqe);
+ pr_err("%s(%d) unsupported send_wr=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_send_wr);
+ pr_err("%s(%d) supported send_wr=0x%x\n",
+ __func__, dev->id, dev->attr.max_wqe);
return -EINVAL;
}
if (!attrs->srq && (attrs->cap.max_recv_wr > dev->attr.max_rqe)) {
- ocrdma_err("%s(%d) unsupported recv_wr=0x%x requested\n",
- __func__, dev->id, attrs->cap.max_recv_wr);
- ocrdma_err("%s(%d) supported recv_wr=0x%x\n",
- __func__, dev->id, dev->attr.max_rqe);
+ pr_err("%s(%d) unsupported recv_wr=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_recv_wr);
+ pr_err("%s(%d) supported recv_wr=0x%x\n",
+ __func__, dev->id, dev->attr.max_rqe);
return -EINVAL;
}
if (attrs->cap.max_inline_data > dev->attr.max_inline_data) {
- ocrdma_err("%s(%d) unsupported inline data size=0x%x"
- " requested\n", __func__, dev->id,
- attrs->cap.max_inline_data);
- ocrdma_err("%s(%d) supported inline data size=0x%x\n",
- __func__, dev->id, dev->attr.max_inline_data);
+ pr_err("%s(%d) unsupported inline data size=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_inline_data);
+ pr_err("%s(%d) supported inline data size=0x%x\n",
+ __func__, dev->id, dev->attr.max_inline_data);
return -EINVAL;
}
if (attrs->cap.max_send_sge > dev->attr.max_send_sge) {
- ocrdma_err("%s(%d) unsupported send_sge=0x%x requested\n",
- __func__, dev->id, attrs->cap.max_send_sge);
- ocrdma_err("%s(%d) supported send_sge=0x%x\n",
- __func__, dev->id, dev->attr.max_send_sge);
+ pr_err("%s(%d) unsupported send_sge=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_send_sge);
+ pr_err("%s(%d) supported send_sge=0x%x\n",
+ __func__, dev->id, dev->attr.max_send_sge);
return -EINVAL;
}
if (attrs->cap.max_recv_sge > dev->attr.max_recv_sge) {
- ocrdma_err("%s(%d) unsupported recv_sge=0x%x requested\n",
- __func__, dev->id, attrs->cap.max_recv_sge);
- ocrdma_err("%s(%d) supported recv_sge=0x%x\n",
- __func__, dev->id, dev->attr.max_recv_sge);
+ pr_err("%s(%d) unsupported recv_sge=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_recv_sge);
+ pr_err("%s(%d) supported recv_sge=0x%x\n",
+ __func__, dev->id, dev->attr.max_recv_sge);
return -EINVAL;
}
/* unprivileged user space cannot create special QP */
if (ibpd->uobject && attrs->qp_type == IB_QPT_GSI) {
- ocrdma_err
+ pr_err
("%s(%d) Userspace can't create special QPs of type=0x%x\n",
__func__, dev->id, attrs->qp_type);
return -EINVAL;
}
/* allow creating only one GSI type of QP */
if (attrs->qp_type == IB_QPT_GSI && dev->gsi_qp_created) {
- ocrdma_err("%s(%d) GSI special QPs already created.\n",
- __func__, dev->id);
+ pr_err("%s(%d) GSI special QPs already created.\n",
+ __func__, dev->id);
return -EINVAL;
}
/* verify consumer QPs are not trying to use GSI QP's CQ */
@@ -896,8 +879,8 @@ static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,
(dev->gsi_sqcq == get_ocrdma_cq(attrs->recv_cq)) ||
(dev->gsi_rqcq == get_ocrdma_cq(attrs->send_cq)) ||
(dev->gsi_rqcq == get_ocrdma_cq(attrs->recv_cq))) {
- ocrdma_err("%s(%d) Consumer QP cannot use GSI CQs.\n",
- __func__, dev->id);
+ pr_err("%s(%d) Consumer QP cannot use GSI CQs.\n",
+ __func__, dev->id);
return -EINVAL;
}
}
@@ -949,7 +932,7 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
}
status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
if (status) {
- ocrdma_err("%s(%d) user copy error.\n", __func__, dev->id);
+ pr_err("%s(%d) user copy error.\n", __func__, dev->id);
goto err;
}
status = ocrdma_add_mmap(pd->uctx, uresp.sq_page_addr[0],
@@ -1023,15 +1006,6 @@ static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp,
qp->state = OCRDMA_QPS_RST;
}
-static void ocrdma_set_qp_use_cnt(struct ocrdma_qp *qp, struct ocrdma_pd *pd)
-{
- atomic_inc(&pd->use_cnt);
- atomic_inc(&qp->sq_cq->use_cnt);
- atomic_inc(&qp->rq_cq->use_cnt);
- if (qp->srq)
- atomic_inc(&qp->srq->use_cnt);
- qp->ibqp.qp_num = qp->id;
-}
static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev,
struct ib_qp_init_attr *attrs)
@@ -1099,7 +1073,7 @@ struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
goto cpy_err;
}
ocrdma_store_gsi_qp_cq(dev, attrs);
- ocrdma_set_qp_use_cnt(qp, pd);
+ qp->ibqp.qp_num = qp->id;
mutex_unlock(&dev->dev_lock);
return &qp->ibqp;
@@ -1112,7 +1086,7 @@ mbx_err:
kfree(qp->wqe_wr_id_tbl);
kfree(qp->rqe_wr_id_tbl);
kfree(qp);
- ocrdma_err("%s(%d) error=%d\n", __func__, dev->id, status);
+ pr_err("%s(%d) error=%d\n", __func__, dev->id, status);
gen_err:
return ERR_PTR(status);
}
@@ -1162,10 +1136,10 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
spin_unlock_irqrestore(&qp->q_lock, flags);
if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) {
- ocrdma_err("%s(%d) invalid attribute mask=0x%x specified for "
- "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
- __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
- old_qps, new_qps);
+ pr_err("%s(%d) invalid attribute mask=0x%x specified for\n"
+ "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
+ __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
+ old_qps, new_qps);
goto param_err;
}
@@ -1475,11 +1449,6 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
ocrdma_del_flush_qp(qp);
- atomic_dec(&qp->pd->use_cnt);
- atomic_dec(&qp->sq_cq->use_cnt);
- atomic_dec(&qp->rq_cq->use_cnt);
- if (qp->srq)
- atomic_dec(&qp->srq->use_cnt);
kfree(qp->wqe_wr_id_tbl);
kfree(qp->rqe_wr_id_tbl);
kfree(qp);
@@ -1565,14 +1534,12 @@ struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd,
goto arm_err;
}
- atomic_set(&srq->use_cnt, 0);
if (udata) {
status = ocrdma_copy_srq_uresp(srq, udata);
if (status)
goto arm_err;
}
- atomic_inc(&pd->use_cnt);
return &srq->ibsrq;
arm_err:
@@ -1618,18 +1585,12 @@ int ocrdma_destroy_srq(struct ib_srq *ibsrq)
srq = get_ocrdma_srq(ibsrq);
dev = srq->dev;
- if (atomic_read(&srq->use_cnt)) {
- ocrdma_err("%s(%d) err, srq=0x%x in use\n",
- __func__, dev->id, srq->id);
- return -EAGAIN;
- }
status = ocrdma_mbx_destroy_srq(dev, srq);
if (srq->pd->uctx)
ocrdma_del_mmap(srq->pd->uctx, (u64) srq->rq.pa, srq->rq.len);
- atomic_dec(&srq->pd->use_cnt);
kfree(srq->idx_bit_fields);
kfree(srq->rqe_wr_id_tbl);
kfree(srq);
@@ -1677,9 +1638,9 @@ static int ocrdma_build_inline_sges(struct ocrdma_qp *qp,
{
if (wr->send_flags & IB_SEND_INLINE) {
if (wr->sg_list[0].length > qp->max_inline_data) {
- ocrdma_err("%s() supported_len=0x%x,"
- " unspported len req=0x%x\n", __func__,
- qp->max_inline_data, wr->sg_list[0].length);
+ pr_err("%s() supported_len=0x%x,\n"
+ " unspported len req=0x%x\n", __func__,
+ qp->max_inline_data, wr->sg_list[0].length);
return -EINVAL;
}
memcpy(sge,
@@ -1773,12 +1734,14 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
spin_lock_irqsave(&qp->q_lock, flags);
if (qp->state != OCRDMA_QPS_RTS && qp->state != OCRDMA_QPS_SQD) {
spin_unlock_irqrestore(&qp->q_lock, flags);
+ *bad_wr = wr;
return -EINVAL;
}
while (wr) {
if (ocrdma_hwq_free_cnt(&qp->sq) == 0 ||
wr->num_sge > qp->sq.max_sges) {
+ *bad_wr = wr;
status = -ENOMEM;
break;
}
@@ -1856,7 +1819,7 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
static void ocrdma_ring_rq_db(struct ocrdma_qp *qp)
{
- u32 val = qp->rq.dbid | (1 << OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp));
+ u32 val = qp->rq.dbid | (1 << ocrdma_get_num_posted_shift(qp));
iowrite32(val, qp->rq_db);
}
@@ -2094,8 +2057,8 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
break;
default:
ibwc->status = IB_WC_GENERAL_ERR;
- ocrdma_err("%s() invalid opcode received = 0x%x\n",
- __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
+ pr_err("%s() invalid opcode received = 0x%x\n",
+ __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
break;
};
}
diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig
index 1e603a375069..d03ca4c1ff25 100644
--- a/drivers/infiniband/hw/qib/Kconfig
+++ b/drivers/infiniband/hw/qib/Kconfig
@@ -5,3 +5,11 @@ config INFINIBAND_QIB
This is a low-level driver for Intel PCIe QLE InfiniBand host
channel adapters. This driver does not support the Intel
HyperTransport card (model QHT7140).
+
+config INFINIBAND_QIB_DCA
+ bool "QIB DCA support"
+ depends on INFINIBAND_QIB && DCA && SMP && GENERIC_HARDIRQS && !(INFINIBAND_QIB=y && DCA=m)
+ default y
+ ---help---
+ Setting this enables DCA support on some Intel chip sets
+ with the iba7322 HCA.
diff --git a/drivers/infiniband/hw/qib/Makefile b/drivers/infiniband/hw/qib/Makefile
index f12d7bb8b39f..57f8103e51f8 100644
--- a/drivers/infiniband/hw/qib/Makefile
+++ b/drivers/infiniband/hw/qib/Makefile
@@ -13,3 +13,4 @@ ib_qib-$(CONFIG_PCI_MSI) += qib_iba6120.o
ib_qib-$(CONFIG_X86_64) += qib_wc_x86_64.o
ib_qib-$(CONFIG_PPC64) += qib_wc_ppc64.o
+ib_qib-$(CONFIG_DEBUG_FS) += qib_debugfs.o
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 4d11575c2010..4a9af795b88f 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1,7 +1,7 @@
#ifndef _QIB_KERNEL_H
#define _QIB_KERNEL_H
/*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -51,6 +51,7 @@
#include <linux/completion.h>
#include <linux/kref.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include "qib_common.h"
#include "qib_verbs.h"
@@ -114,6 +115,11 @@ struct qib_eep_log_mask {
/*
* Below contains all data related to a single context (formerly called port).
*/
+
+#ifdef CONFIG_DEBUG_FS
+struct qib_opcode_stats_perctx;
+#endif
+
struct qib_ctxtdata {
void **rcvegrbuf;
dma_addr_t *rcvegrbuf_phys;
@@ -154,6 +160,8 @@ struct qib_ctxtdata {
*/
/* instead of calculating it */
unsigned ctxt;
+ /* local node of context */
+ int node_id;
/* non-zero if ctxt is being shared. */
u16 subctxt_cnt;
/* non-zero if ctxt is being shared. */
@@ -222,12 +230,15 @@ struct qib_ctxtdata {
u8 redirect_seq_cnt;
/* ctxt rcvhdrq head offset */
u32 head;
- u32 pkt_count;
/* lookaside fields */
struct qib_qp *lookaside_qp;
u32 lookaside_qpn;
/* QPs waiting for context processing */
struct list_head qp_wait_list;
+#ifdef CONFIG_DEBUG_FS
+ /* verbs stats per CTX */
+ struct qib_opcode_stats_perctx *opstats;
+#endif
};
struct qib_sge_state;
@@ -428,9 +439,19 @@ struct qib_verbs_txreq {
#define ACTIVITY_TIMER 5
#define MAX_NAME_SIZE 64
+
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+struct qib_irq_notify;
+#endif
+
struct qib_msix_entry {
struct msix_entry msix;
void *arg;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ int dca;
+ int rcv;
+ struct qib_irq_notify *notifier;
+#endif
char name[MAX_NAME_SIZE];
cpumask_var_t mask;
};
@@ -828,6 +849,9 @@ struct qib_devdata {
struct qib_ctxtdata *);
void (*f_writescratch)(struct qib_devdata *, u32);
int (*f_tempsense_rd)(struct qib_devdata *, int regnum);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ int (*f_notify_dca)(struct qib_devdata *, unsigned long event);
+#endif
char *boardname; /* human readable board info */
@@ -1075,6 +1099,10 @@ struct qib_devdata {
u16 psxmitwait_check_rate;
/* high volume overflow errors defered to tasklet */
struct tasklet_struct error_tasklet;
+ /* per device cq worker */
+ struct kthread_worker *worker;
+
+ int assigned_node_id; /* NUMA node closest to HCA */
};
/* hol_state values */
@@ -1154,7 +1182,7 @@ int qib_create_rcvhdrq(struct qib_devdata *, struct qib_ctxtdata *);
int qib_setup_eagerbufs(struct qib_ctxtdata *);
void qib_set_ctxtcnt(struct qib_devdata *);
int qib_create_ctxts(struct qib_devdata *dd);
-struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32);
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32, int);
void qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8);
void qib_free_ctxtdata(struct qib_devdata *, struct qib_ctxtdata *);
@@ -1320,7 +1348,7 @@ static inline int __qib_sdma_running(struct qib_pportdata *ppd)
return ppd->sdma_state.current_state == qib_sdma_state_s99_running;
}
int qib_sdma_running(struct qib_pportdata *);
-
+void dump_sdma_state(struct qib_pportdata *ppd);
void __qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
void qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
@@ -1445,6 +1473,7 @@ extern unsigned qib_n_krcv_queues;
extern unsigned qib_sdma_fetch_arb;
extern unsigned qib_compat_ddr_negotiate;
extern int qib_special_trigger;
+extern unsigned qib_numa_aware;
extern struct mutex qib_mutex;
@@ -1474,27 +1503,23 @@ extern struct mutex qib_mutex;
* first to avoid possible serial port delays from printk.
*/
#define qib_early_err(dev, fmt, ...) \
- do { \
- dev_err(dev, fmt, ##__VA_ARGS__); \
- } while (0)
+ dev_err(dev, fmt, ##__VA_ARGS__)
#define qib_dev_err(dd, fmt, ...) \
- do { \
- dev_err(&(dd)->pcidev->dev, "%s: " fmt, \
- qib_get_unit_name((dd)->unit), ##__VA_ARGS__); \
- } while (0)
+ dev_err(&(dd)->pcidev->dev, "%s: " fmt, \
+ qib_get_unit_name((dd)->unit), ##__VA_ARGS__)
+
+#define qib_dev_warn(dd, fmt, ...) \
+ dev_warn(&(dd)->pcidev->dev, "%s: " fmt, \
+ qib_get_unit_name((dd)->unit), ##__VA_ARGS__)
#define qib_dev_porterr(dd, port, fmt, ...) \
- do { \
- dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \
- qib_get_unit_name((dd)->unit), (dd)->unit, (port), \
- ##__VA_ARGS__); \
- } while (0)
+ dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \
+ qib_get_unit_name((dd)->unit), (dd)->unit, (port), \
+ ##__VA_ARGS__)
#define qib_devinfo(pcidev, fmt, ...) \
- do { \
- dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__); \
- } while (0)
+ dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__)
/*
* this is used for formatting hw error messages...
diff --git a/drivers/infiniband/hw/qib/qib_common.h b/drivers/infiniband/hw/qib/qib_common.h
index d39e0183ff82..4f255b723ffd 100644
--- a/drivers/infiniband/hw/qib/qib_common.h
+++ b/drivers/infiniband/hw/qib/qib_common.h
@@ -279,7 +279,7 @@ struct qib_base_info {
* may not be implemented; the user code must deal with this if it
* cares, or it must abort after initialization reports the difference.
*/
-#define QIB_USER_SWMINOR 11
+#define QIB_USER_SWMINOR 12
#define QIB_USER_SWVERSION ((QIB_USER_SWMAJOR << 16) | QIB_USER_SWMINOR)
diff --git a/drivers/infiniband/hw/qib/qib_cq.c b/drivers/infiniband/hw/qib/qib_cq.c
index 5246aa486bbe..ab4e11cfab15 100644
--- a/drivers/infiniband/hw/qib/qib_cq.c
+++ b/drivers/infiniband/hw/qib/qib_cq.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
* Copyright (c) 2006, 2007, 2008, 2010 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -34,8 +35,10 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/kthread.h>
#include "qib_verbs.h"
+#include "qib.h"
/**
* qib_cq_enter - add a new entry to the completion queue
@@ -102,13 +105,18 @@ void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited)
if (cq->notify == IB_CQ_NEXT_COMP ||
(cq->notify == IB_CQ_SOLICITED &&
(solicited || entry->status != IB_WC_SUCCESS))) {
- cq->notify = IB_CQ_NONE;
- cq->triggered++;
+ struct kthread_worker *worker;
/*
* This will cause send_complete() to be called in
* another thread.
*/
- queue_work(qib_cq_wq, &cq->comptask);
+ smp_rmb();
+ worker = cq->dd->worker;
+ if (likely(worker)) {
+ cq->notify = IB_CQ_NONE;
+ cq->triggered++;
+ queue_kthread_work(worker, &cq->comptask);
+ }
}
spin_unlock_irqrestore(&cq->lock, flags);
@@ -163,7 +171,7 @@ bail:
return npolled;
}
-static void send_complete(struct work_struct *work)
+static void send_complete(struct kthread_work *work)
{
struct qib_cq *cq = container_of(work, struct qib_cq, comptask);
@@ -287,11 +295,12 @@ struct ib_cq *qib_create_cq(struct ib_device *ibdev, int entries,
* The number of entries should be >= the number requested or return
* an error.
*/
+ cq->dd = dd_from_dev(dev);
cq->ibcq.cqe = entries;
cq->notify = IB_CQ_NONE;
cq->triggered = 0;
spin_lock_init(&cq->lock);
- INIT_WORK(&cq->comptask, send_complete);
+ init_kthread_work(&cq->comptask, send_complete);
wc->head = 0;
wc->tail = 0;
cq->queue = wc;
@@ -323,7 +332,7 @@ int qib_destroy_cq(struct ib_cq *ibcq)
struct qib_ibdev *dev = to_idev(ibcq->device);
struct qib_cq *cq = to_icq(ibcq);
- flush_work(&cq->comptask);
+ flush_kthread_work(&cq->comptask);
spin_lock(&dev->n_cqs_lock);
dev->n_cqs_allocated--;
spin_unlock(&dev->n_cqs_lock);
@@ -483,3 +492,49 @@ bail_free:
bail:
return ret;
}
+
+int qib_cq_init(struct qib_devdata *dd)
+{
+ int ret = 0;
+ int cpu;
+ struct task_struct *task;
+
+ if (dd->worker)
+ return 0;
+ dd->worker = kzalloc(sizeof(*dd->worker), GFP_KERNEL);
+ if (!dd->worker)
+ return -ENOMEM;
+ init_kthread_worker(dd->worker);
+ task = kthread_create_on_node(
+ kthread_worker_fn,
+ dd->worker,
+ dd->assigned_node_id,
+ "qib_cq%d", dd->unit);
+ if (IS_ERR(task))
+ goto task_fail;
+ cpu = cpumask_first(cpumask_of_node(dd->assigned_node_id));
+ kthread_bind(task, cpu);
+ wake_up_process(task);
+out:
+ return ret;
+task_fail:
+ ret = PTR_ERR(task);
+ kfree(dd->worker);
+ dd->worker = NULL;
+ goto out;
+}
+
+void qib_cq_exit(struct qib_devdata *dd)
+{
+ struct kthread_worker *worker;
+
+ worker = dd->worker;
+ if (!worker)
+ return;
+ /* blocks future queuing from send_complete() */
+ dd->worker = NULL;
+ smp_wmb();
+ flush_kthread_worker(worker);
+ kthread_stop(worker->task);
+ kfree(worker);
+}
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.c b/drivers/infiniband/hw/qib/qib_debugfs.c
new file mode 100644
index 000000000000..799a0c3bffc4
--- /dev/null
+++ b/drivers/infiniband/hw/qib/qib_debugfs.c
@@ -0,0 +1,283 @@
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+
+#include "qib.h"
+#include "qib_verbs.h"
+#include "qib_debugfs.h"
+
+static struct dentry *qib_dbg_root;
+
+#define DEBUGFS_FILE(name) \
+static const struct seq_operations _##name##_seq_ops = { \
+ .start = _##name##_seq_start, \
+ .next = _##name##_seq_next, \
+ .stop = _##name##_seq_stop, \
+ .show = _##name##_seq_show \
+}; \
+static int _##name##_open(struct inode *inode, struct file *s) \
+{ \
+ struct seq_file *seq; \
+ int ret; \
+ ret = seq_open(s, &_##name##_seq_ops); \
+ if (ret) \
+ return ret; \
+ seq = s->private_data; \
+ seq->private = inode->i_private; \
+ return 0; \
+} \
+static const struct file_operations _##name##_file_ops = { \
+ .owner = THIS_MODULE, \
+ .open = _##name##_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = seq_release \
+};
+
+#define DEBUGFS_FILE_CREATE(name) \
+do { \
+ struct dentry *ent; \
+ ent = debugfs_create_file(#name , 0400, ibd->qib_ibdev_dbg, \
+ ibd, &_##name##_file_ops); \
+ if (!ent) \
+ pr_warn("create of " #name " failed\n"); \
+} while (0)
+
+static void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct qib_opcode_stats_perctx *opstats;
+
+ if (*pos >= ARRAY_SIZE(opstats->stats))
+ return NULL;
+ return pos;
+}
+
+static void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct qib_opcode_stats_perctx *opstats;
+
+ ++*pos;
+ if (*pos >= ARRAY_SIZE(opstats->stats))
+ return NULL;
+ return pos;
+}
+
+
+static void _opcode_stats_seq_stop(struct seq_file *s, void *v)
+{
+ /* nothing allocated */
+}
+
+static int _opcode_stats_seq_show(struct seq_file *s, void *v)
+{
+ loff_t *spos = v;
+ loff_t i = *spos, j;
+ u64 n_packets = 0, n_bytes = 0;
+ struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+ struct qib_devdata *dd = dd_from_dev(ibd);
+
+ for (j = 0; j < dd->first_user_ctxt; j++) {
+ if (!dd->rcd[j])
+ continue;
+ n_packets += dd->rcd[j]->opstats->stats[i].n_packets;
+ n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes;
+ }
+ if (!n_packets && !n_bytes)
+ return SEQ_SKIP;
+ seq_printf(s, "%02llx %llu/%llu\n", i,
+ (unsigned long long) n_packets,
+ (unsigned long long) n_bytes);
+
+ return 0;
+}
+
+DEBUGFS_FILE(opcode_stats)
+
+static void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+ struct qib_devdata *dd = dd_from_dev(ibd);
+
+ if (!*pos)
+ return SEQ_START_TOKEN;
+ if (*pos >= dd->first_user_ctxt)
+ return NULL;
+ return pos;
+}
+
+static void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+ struct qib_devdata *dd = dd_from_dev(ibd);
+
+ if (v == SEQ_START_TOKEN)
+ return pos;
+
+ ++*pos;
+ if (*pos >= dd->first_user_ctxt)
+ return NULL;
+ return pos;
+}
+
+static void _ctx_stats_seq_stop(struct seq_file *s, void *v)
+{
+ /* nothing allocated */
+}
+
+static int _ctx_stats_seq_show(struct seq_file *s, void *v)
+{
+ loff_t *spos;
+ loff_t i, j;
+ u64 n_packets = 0;
+ struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+ struct qib_devdata *dd = dd_from_dev(ibd);
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(s, "Ctx:npkts\n");
+ return 0;
+ }
+
+ spos = v;
+ i = *spos;
+
+ if (!dd->rcd[i])
+ return SEQ_SKIP;
+
+ for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++)
+ n_packets += dd->rcd[i]->opstats->stats[j].n_packets;
+
+ if (!n_packets)
+ return SEQ_SKIP;
+
+ seq_printf(s, " %llu:%llu\n", i, n_packets);
+ return 0;
+}
+
+DEBUGFS_FILE(ctx_stats)
+
+static void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct qib_qp_iter *iter;
+ loff_t n = *pos;
+
+ iter = qib_qp_iter_init(s->private);
+ if (!iter)
+ return NULL;
+
+ while (n--) {
+ if (qib_qp_iter_next(iter)) {
+ kfree(iter);
+ return NULL;
+ }
+ }
+
+ return iter;
+}
+
+static void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr,
+ loff_t *pos)
+{
+ struct qib_qp_iter *iter = iter_ptr;
+
+ (*pos)++;
+
+ if (qib_qp_iter_next(iter)) {
+ kfree(iter);
+ return NULL;
+ }
+
+ return iter;
+}
+
+static void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr)
+{
+ /* nothing for now */
+}
+
+static int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr)
+{
+ struct qib_qp_iter *iter = iter_ptr;
+
+ if (!iter)
+ return 0;
+
+ qib_qp_iter_print(s, iter);
+
+ return 0;
+}
+
+DEBUGFS_FILE(qp_stats)
+
+void qib_dbg_ibdev_init(struct qib_ibdev *ibd)
+{
+ char name[10];
+
+ snprintf(name, sizeof(name), "qib%d", dd_from_dev(ibd)->unit);
+ ibd->qib_ibdev_dbg = debugfs_create_dir(name, qib_dbg_root);
+ if (!ibd->qib_ibdev_dbg) {
+ pr_warn("create of %s failed\n", name);
+ return;
+ }
+ DEBUGFS_FILE_CREATE(opcode_stats);
+ DEBUGFS_FILE_CREATE(ctx_stats);
+ DEBUGFS_FILE_CREATE(qp_stats);
+ return;
+}
+
+void qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
+{
+ if (!qib_dbg_root)
+ goto out;
+ debugfs_remove_recursive(ibd->qib_ibdev_dbg);
+out:
+ ibd->qib_ibdev_dbg = NULL;
+}
+
+void qib_dbg_init(void)
+{
+ qib_dbg_root = debugfs_create_dir(QIB_DRV_NAME, NULL);
+ if (!qib_dbg_root)
+ pr_warn("init of debugfs failed\n");
+}
+
+void qib_dbg_exit(void)
+{
+ debugfs_remove_recursive(qib_dbg_root);
+ qib_dbg_root = NULL;
+}
+
+#endif
+
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.h b/drivers/infiniband/hw/qib/qib_debugfs.h
new file mode 100644
index 000000000000..7ae983a91b8b
--- /dev/null
+++ b/drivers/infiniband/hw/qib/qib_debugfs.h
@@ -0,0 +1,45 @@
+#ifndef _QIB_DEBUGFS_H
+#define _QIB_DEBUGFS_H
+
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct qib_ibdev;
+void qib_dbg_ibdev_init(struct qib_ibdev *ibd);
+void qib_dbg_ibdev_exit(struct qib_ibdev *ibd);
+void qib_dbg_init(void);
+void qib_dbg_exit(void);
+
+#endif
+
+#endif /* _QIB_DEBUGFS_H */
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 216092477dfc..5bee08f16d74 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -558,7 +558,6 @@ move_along:
}
rcd->head = l;
- rcd->pkt_count += i;
/*
* Iterate over all QPs waiting to respond.
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index 9dd0bc89c3aa..b51a51486cb8 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -1155,6 +1155,49 @@ static unsigned int qib_poll(struct file *fp, struct poll_table_struct *pt)
return pollflag;
}
+static void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd)
+{
+ struct qib_filedata *fd = fp->private_data;
+ const unsigned int weight = cpumask_weight(&current->cpus_allowed);
+ const struct cpumask *local_mask = cpumask_of_pcibus(dd->pcidev->bus);
+ int local_cpu;
+
+ /*
+ * If process has NOT already set it's affinity, select and
+ * reserve a processor for it on the local NUMA node.
+ */
+ if ((weight >= qib_cpulist_count) &&
+ (cpumask_weight(local_mask) <= qib_cpulist_count)) {
+ for_each_cpu(local_cpu, local_mask)
+ if (!test_and_set_bit(local_cpu, qib_cpulist)) {
+ fd->rec_cpu_num = local_cpu;
+ return;
+ }
+ }
+
+ /*
+ * If process has NOT already set it's affinity, select and
+ * reserve a processor for it, as a rendevous for all
+ * users of the driver. If they don't actually later
+ * set affinity to this cpu, or set it to some other cpu,
+ * it just means that sooner or later we don't recommend
+ * a cpu, and let the scheduler do it's best.
+ */
+ if (weight >= qib_cpulist_count) {
+ int cpu;
+ cpu = find_first_zero_bit(qib_cpulist,
+ qib_cpulist_count);
+ if (cpu == qib_cpulist_count)
+ qib_dev_err(dd,
+ "no cpus avail for affinity PID %u\n",
+ current->pid);
+ else {
+ __set_bit(cpu, qib_cpulist);
+ fd->rec_cpu_num = cpu;
+ }
+ }
+}
+
/*
* Check that userland and driver are compatible for subcontexts.
*/
@@ -1259,12 +1302,20 @@ bail:
static int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
struct file *fp, const struct qib_user_info *uinfo)
{
+ struct qib_filedata *fd = fp->private_data;
struct qib_devdata *dd = ppd->dd;
struct qib_ctxtdata *rcd;
void *ptmp = NULL;
int ret;
+ int numa_id;
+
+ assign_ctxt_affinity(fp, dd);
- rcd = qib_create_ctxtdata(ppd, ctxt);
+ numa_id = qib_numa_aware ? ((fd->rec_cpu_num != -1) ?
+ cpu_to_node(fd->rec_cpu_num) :
+ numa_node_id()) : dd->assigned_node_id;
+
+ rcd = qib_create_ctxtdata(ppd, ctxt, numa_id);
/*
* Allocate memory for use in qib_tid_update() at open to
@@ -1296,6 +1347,9 @@ static int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
goto bail;
bailerr:
+ if (fd->rec_cpu_num != -1)
+ __clear_bit(fd->rec_cpu_num, qib_cpulist);
+
dd->rcd[ctxt] = NULL;
kfree(rcd);
kfree(ptmp);
@@ -1485,6 +1539,57 @@ static int qib_open(struct inode *in, struct file *fp)
return fp->private_data ? 0 : -ENOMEM;
}
+static int find_hca(unsigned int cpu, int *unit)
+{
+ int ret = 0, devmax, npresent, nup, ndev;
+
+ *unit = -1;
+
+ devmax = qib_count_units(&npresent, &nup);
+ if (!npresent) {
+ ret = -ENXIO;
+ goto done;
+ }
+ if (!nup) {
+ ret = -ENETDOWN;
+ goto done;
+ }
+ for (ndev = 0; ndev < devmax; ndev++) {
+ struct qib_devdata *dd = qib_lookup(ndev);
+ if (dd) {
+ if (pcibus_to_node(dd->pcidev->bus) < 0) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (cpu_to_node(cpu) ==
+ pcibus_to_node(dd->pcidev->bus)) {
+ *unit = ndev;
+ goto done;
+ }
+ }
+ }
+done:
+ return ret;
+}
+
+static int do_qib_user_sdma_queue_create(struct file *fp)
+{
+ struct qib_filedata *fd = fp->private_data;
+ struct qib_ctxtdata *rcd = fd->rcd;
+ struct qib_devdata *dd = rcd->dd;
+
+ if (dd->flags & QIB_HAS_SEND_DMA)
+
+ fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
+ dd->unit,
+ rcd->ctxt,
+ fd->subctxt);
+ if (!fd->pq)
+ return -ENOMEM;
+
+ return 0;
+}
+
/*
* Get ctxt early, so can set affinity prior to memory allocation.
*/
@@ -1517,61 +1622,36 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
if (qib_compatible_subctxts(swmajor, swminor) &&
uinfo->spu_subctxt_cnt) {
ret = find_shared_ctxt(fp, uinfo);
- if (ret) {
- if (ret > 0)
- ret = 0;
- goto done_chk_sdma;
+ if (ret > 0) {
+ ret = do_qib_user_sdma_queue_create(fp);
+ if (!ret)
+ assign_ctxt_affinity(fp, (ctxt_fp(fp))->dd);
+ goto done_ok;
}
}
i_minor = iminor(file_inode(fp)) - QIB_USER_MINOR_BASE;
if (i_minor)
ret = find_free_ctxt(i_minor - 1, fp, uinfo);
- else
+ else {
+ int unit;
+ const unsigned int cpu = cpumask_first(&current->cpus_allowed);
+ const unsigned int weight =
+ cpumask_weight(&current->cpus_allowed);
+
+ if (weight == 1 && !test_bit(cpu, qib_cpulist))
+ if (!find_hca(cpu, &unit) && unit >= 0)
+ if (!find_free_ctxt(unit, fp, uinfo)) {
+ ret = 0;
+ goto done_chk_sdma;
+ }
ret = get_a_ctxt(fp, uinfo, alg);
-
-done_chk_sdma:
- if (!ret) {
- struct qib_filedata *fd = fp->private_data;
- const struct qib_ctxtdata *rcd = fd->rcd;
- const struct qib_devdata *dd = rcd->dd;
- unsigned int weight;
-
- if (dd->flags & QIB_HAS_SEND_DMA) {
- fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
- dd->unit,
- rcd->ctxt,
- fd->subctxt);
- if (!fd->pq)
- ret = -ENOMEM;
- }
-
- /*
- * If process has NOT already set it's affinity, select and
- * reserve a processor for it, as a rendezvous for all
- * users of the driver. If they don't actually later
- * set affinity to this cpu, or set it to some other cpu,
- * it just means that sooner or later we don't recommend
- * a cpu, and let the scheduler do it's best.
- */
- weight = cpumask_weight(tsk_cpus_allowed(current));
- if (!ret && weight >= qib_cpulist_count) {
- int cpu;
- cpu = find_first_zero_bit(qib_cpulist,
- qib_cpulist_count);
- if (cpu != qib_cpulist_count) {
- __set_bit(cpu, qib_cpulist);
- fd->rec_cpu_num = cpu;
- }
- } else if (weight == 1 &&
- test_bit(cpumask_first(tsk_cpus_allowed(current)),
- qib_cpulist))
- qib_devinfo(dd->pcidev,
- "%s PID %u affinity set to cpu %d; already allocated\n",
- current->comm, current->pid,
- cpumask_first(tsk_cpus_allowed(current)));
}
+done_chk_sdma:
+ if (!ret)
+ ret = do_qib_user_sdma_queue_create(fp);
+done_ok:
mutex_unlock(&qib_mutex);
done:
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index 0232ae56b1fa..84e593d6007b 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -3464,6 +3464,13 @@ static int qib_6120_tempsense_rd(struct qib_devdata *dd, int regnum)
return -ENXIO;
}
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static int qib_6120_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+ return 0;
+}
+#endif
+
/* Dummy function, as 6120 boards never disable EEPROM Write */
static int qib_6120_eeprom_wen(struct qib_devdata *dd, int wen)
{
@@ -3539,6 +3546,9 @@ struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
dd->f_xgxs_reset = qib_6120_xgxs_reset;
dd->f_writescratch = writescratch;
dd->f_tempsense_rd = qib_6120_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dd->f_notify_dca = qib_6120_notify_dca;
+#endif
/*
* Do remaining pcie setup and save pcie values in dd.
* Any error printing is already done by the init code.
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 64d0ecb90cdc..454c2e7668fe 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -4513,6 +4513,13 @@ bail:
return ret;
}
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static int qib_7220_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+ return 0;
+}
+#endif
+
/* Dummy function, as 7220 boards never disable EEPROM Write */
static int qib_7220_eeprom_wen(struct qib_devdata *dd, int wen)
{
@@ -4587,6 +4594,9 @@ struct qib_devdata *qib_init_iba7220_funcs(struct pci_dev *pdev,
dd->f_xgxs_reset = qib_7220_xgxs_reset;
dd->f_writescratch = writescratch;
dd->f_tempsense_rd = qib_7220_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dd->f_notify_dca = qib_7220_notify_dca;
+#endif
/*
* Do remaining pcie setup and save pcie values in dd.
* Any error printing is already done by the init code.
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 3f6b21e9dc11..21e8b09d4bf8 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -44,6 +44,9 @@
#include <linux/module.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_smi.h>
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+#include <linux/dca.h>
+#endif
#include "qib.h"
#include "qib_7322_regs.h"
@@ -80,6 +83,7 @@ static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
static void serdes_7322_los_enable(struct qib_pportdata *, int);
static int serdes_7322_init_old(struct qib_pportdata *);
static int serdes_7322_init_new(struct qib_pportdata *);
+static void dump_sdma_7322_state(struct qib_pportdata *);
#define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
@@ -519,6 +523,14 @@ static const u8 qib_7322_physportstate[0x20] = {
[0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
};
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+struct qib_irq_notify {
+ int rcv;
+ void *arg;
+ struct irq_affinity_notify notify;
+};
+#endif
+
struct qib_chip_specific {
u64 __iomem *cregbase;
u64 *cntrs;
@@ -546,6 +558,12 @@ struct qib_chip_specific {
u32 lastbuf_for_pio;
u32 stay_in_freeze;
u32 recovery_ports_initted;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ u32 dca_ctrl;
+ int rhdr_cpu[18];
+ int sdma_cpu[2];
+ u64 dca_rcvhdr_ctrl[5]; /* B, C, D, E, F */
+#endif
struct qib_msix_entry *msix_entries;
unsigned long *sendchkenable;
unsigned long *sendgrhchk;
@@ -573,7 +591,7 @@ struct vendor_txdds_ent {
static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
#define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
-#define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */
+#define TXDDS_EXTRA_SZ 18 /* number of extra tx settings entries */
#define TXDDS_MFG_SZ 2 /* number of mfg tx settings entries */
#define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
@@ -635,6 +653,7 @@ struct qib_chippport_specific {
u8 ibmalfusesnap;
struct qib_qsfp_data qsfp_data;
char epmsgbuf[192]; /* for port error interrupt msg buffer */
+ char sdmamsgbuf[192]; /* for per-port sdma error messages */
};
static struct {
@@ -642,28 +661,76 @@ static struct {
irq_handler_t handler;
int lsb;
int port; /* 0 if not port-specific, else port # */
+ int dca;
} irq_table[] = {
- { "", qib_7322intr, -1, 0 },
+ { "", qib_7322intr, -1, 0, 0 },
{ " (buf avail)", qib_7322bufavail,
- SYM_LSB(IntStatus, SendBufAvail), 0 },
+ SYM_LSB(IntStatus, SendBufAvail), 0, 0},
{ " (sdma 0)", sdma_intr,
- SYM_LSB(IntStatus, SDmaInt_0), 1 },
+ SYM_LSB(IntStatus, SDmaInt_0), 1, 1 },
{ " (sdma 1)", sdma_intr,
- SYM_LSB(IntStatus, SDmaInt_1), 2 },
+ SYM_LSB(IntStatus, SDmaInt_1), 2, 1 },
{ " (sdmaI 0)", sdma_idle_intr,
- SYM_LSB(IntStatus, SDmaIdleInt_0), 1 },
+ SYM_LSB(IntStatus, SDmaIdleInt_0), 1, 1},
{ " (sdmaI 1)", sdma_idle_intr,
- SYM_LSB(IntStatus, SDmaIdleInt_1), 2 },
+ SYM_LSB(IntStatus, SDmaIdleInt_1), 2, 1},
{ " (sdmaP 0)", sdma_progress_intr,
- SYM_LSB(IntStatus, SDmaProgressInt_0), 1 },
+ SYM_LSB(IntStatus, SDmaProgressInt_0), 1, 1 },
{ " (sdmaP 1)", sdma_progress_intr,
- SYM_LSB(IntStatus, SDmaProgressInt_1), 2 },
+ SYM_LSB(IntStatus, SDmaProgressInt_1), 2, 1 },
{ " (sdmaC 0)", sdma_cleanup_intr,
- SYM_LSB(IntStatus, SDmaCleanupDone_0), 1 },
+ SYM_LSB(IntStatus, SDmaCleanupDone_0), 1, 0 },
{ " (sdmaC 1)", sdma_cleanup_intr,
- SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 },
+ SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 , 0},
};
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static const struct dca_reg_map {
+ int shadow_inx;
+ int lsb;
+ u64 mask;
+ u16 regno;
+} dca_rcvhdr_reg_map[] = {
+ { 0, SYM_LSB(DCACtrlB, RcvHdrq0DCAOPH),
+ ~SYM_MASK(DCACtrlB, RcvHdrq0DCAOPH) , KREG_IDX(DCACtrlB) },
+ { 0, SYM_LSB(DCACtrlB, RcvHdrq1DCAOPH),
+ ~SYM_MASK(DCACtrlB, RcvHdrq1DCAOPH) , KREG_IDX(DCACtrlB) },
+ { 0, SYM_LSB(DCACtrlB, RcvHdrq2DCAOPH),
+ ~SYM_MASK(DCACtrlB, RcvHdrq2DCAOPH) , KREG_IDX(DCACtrlB) },
+ { 0, SYM_LSB(DCACtrlB, RcvHdrq3DCAOPH),
+ ~SYM_MASK(DCACtrlB, RcvHdrq3DCAOPH) , KREG_IDX(DCACtrlB) },
+ { 1, SYM_LSB(DCACtrlC, RcvHdrq4DCAOPH),
+ ~SYM_MASK(DCACtrlC, RcvHdrq4DCAOPH) , KREG_IDX(DCACtrlC) },
+ { 1, SYM_LSB(DCACtrlC, RcvHdrq5DCAOPH),
+ ~SYM_MASK(DCACtrlC, RcvHdrq5DCAOPH) , KREG_IDX(DCACtrlC) },
+ { 1, SYM_LSB(DCACtrlC, RcvHdrq6DCAOPH),
+ ~SYM_MASK(DCACtrlC, RcvHdrq6DCAOPH) , KREG_IDX(DCACtrlC) },
+ { 1, SYM_LSB(DCACtrlC, RcvHdrq7DCAOPH),
+ ~SYM_MASK(DCACtrlC, RcvHdrq7DCAOPH) , KREG_IDX(DCACtrlC) },
+ { 2, SYM_LSB(DCACtrlD, RcvHdrq8DCAOPH),
+ ~SYM_MASK(DCACtrlD, RcvHdrq8DCAOPH) , KREG_IDX(DCACtrlD) },
+ { 2, SYM_LSB(DCACtrlD, RcvHdrq9DCAOPH),
+ ~SYM_MASK(DCACtrlD, RcvHdrq9DCAOPH) , KREG_IDX(DCACtrlD) },
+ { 2, SYM_LSB(DCACtrlD, RcvHdrq10DCAOPH),
+ ~SYM_MASK(DCACtrlD, RcvHdrq10DCAOPH) , KREG_IDX(DCACtrlD) },
+ { 2, SYM_LSB(DCACtrlD, RcvHdrq11DCAOPH),
+ ~SYM_MASK(DCACtrlD, RcvHdrq11DCAOPH) , KREG_IDX(DCACtrlD) },
+ { 3, SYM_LSB(DCACtrlE, RcvHdrq12DCAOPH),
+ ~SYM_MASK(DCACtrlE, RcvHdrq12DCAOPH) , KREG_IDX(DCACtrlE) },
+ { 3, SYM_LSB(DCACtrlE, RcvHdrq13DCAOPH),
+ ~SYM_MASK(DCACtrlE, RcvHdrq13DCAOPH) , KREG_IDX(DCACtrlE) },
+ { 3, SYM_LSB(DCACtrlE, RcvHdrq14DCAOPH),
+ ~SYM_MASK(DCACtrlE, RcvHdrq14DCAOPH) , KREG_IDX(DCACtrlE) },
+ { 3, SYM_LSB(DCACtrlE, RcvHdrq15DCAOPH),
+ ~SYM_MASK(DCACtrlE, RcvHdrq15DCAOPH) , KREG_IDX(DCACtrlE) },
+ { 4, SYM_LSB(DCACtrlF, RcvHdrq16DCAOPH),
+ ~SYM_MASK(DCACtrlF, RcvHdrq16DCAOPH) , KREG_IDX(DCACtrlF) },
+ { 4, SYM_LSB(DCACtrlF, RcvHdrq17DCAOPH),
+ ~SYM_MASK(DCACtrlF, RcvHdrq17DCAOPH) , KREG_IDX(DCACtrlF) },
+};
+#endif
+
/* ibcctrl bits */
#define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
/* cycle through TS1/TS2 till OK */
@@ -686,6 +753,13 @@ static void write_7322_init_portregs(struct qib_pportdata *);
static void setup_7322_link_recovery(struct qib_pportdata *, u32);
static void check_7322_rxe_status(struct qib_pportdata *);
static u32 __iomem *qib_7322_getsendbuf(struct qib_pportdata *, u64, u32 *);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static void qib_setup_dca(struct qib_devdata *dd);
+static void setup_dca_notifier(struct qib_devdata *dd,
+ struct qib_msix_entry *m);
+static void reset_dca_notifier(struct qib_devdata *dd,
+ struct qib_msix_entry *m);
+#endif
/**
* qib_read_ureg32 - read 32-bit virtualized per-context register
@@ -1529,6 +1603,15 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
spin_lock_irqsave(&ppd->sdma_lock, flags);
+ if (errs != QIB_E_P_SDMAHALT) {
+ /* SDMA errors have QIB_E_P_SDMAHALT and another bit set */
+ qib_dev_porterr(dd, ppd->port,
+ "SDMA %s 0x%016llx %s\n",
+ qib_sdma_state_names[ppd->sdma_state.current_state],
+ errs, ppd->cpspec->sdmamsgbuf);
+ dump_sdma_7322_state(ppd);
+ }
+
switch (ppd->sdma_state.current_state) {
case qib_sdma_state_s00_hw_down:
break;
@@ -2084,6 +2167,29 @@ static void qib_7322_handle_hwerrors(struct qib_devdata *dd, char *msg,
qib_dev_err(dd, "%s hardware error\n", msg);
+ if (hwerrs &
+ (SYM_MASK(HwErrMask, SDmaMemReadErrMask_0) |
+ SYM_MASK(HwErrMask, SDmaMemReadErrMask_1))) {
+ int pidx = 0;
+ int err;
+ unsigned long flags;
+ struct qib_pportdata *ppd = dd->pport;
+ for (; pidx < dd->num_pports; ++pidx, ppd++) {
+ err = 0;
+ if (pidx == 0 && (hwerrs &
+ SYM_MASK(HwErrMask, SDmaMemReadErrMask_0)))
+ err++;
+ if (pidx == 1 && (hwerrs &
+ SYM_MASK(HwErrMask, SDmaMemReadErrMask_1)))
+ err++;
+ if (err) {
+ spin_lock_irqsave(&ppd->sdma_lock, flags);
+ dump_sdma_7322_state(ppd);
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ }
+ }
+ }
+
if (isfatal && !dd->diag_client) {
qib_dev_err(dd,
"Fatal Hardware Error, no longer usable, SN %.16s\n",
@@ -2558,6 +2664,162 @@ static void qib_setup_7322_setextled(struct qib_pportdata *ppd, u32 on)
qib_write_kreg_port(ppd, krp_rcvpktledcnt, ledblink);
}
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static int qib_7322_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+ switch (event) {
+ case DCA_PROVIDER_ADD:
+ if (dd->flags & QIB_DCA_ENABLED)
+ break;
+ if (!dca_add_requester(&dd->pcidev->dev)) {
+ qib_devinfo(dd->pcidev, "DCA enabled\n");
+ dd->flags |= QIB_DCA_ENABLED;
+ qib_setup_dca(dd);
+ }
+ break;
+ case DCA_PROVIDER_REMOVE:
+ if (dd->flags & QIB_DCA_ENABLED) {
+ dca_remove_requester(&dd->pcidev->dev);
+ dd->flags &= ~QIB_DCA_ENABLED;
+ dd->cspec->dca_ctrl = 0;
+ qib_write_kreg(dd, KREG_IDX(DCACtrlA),
+ dd->cspec->dca_ctrl);
+ }
+ break;
+ }
+ return 0;
+}
+
+static void qib_update_rhdrq_dca(struct qib_ctxtdata *rcd, int cpu)
+{
+ struct qib_devdata *dd = rcd->dd;
+ struct qib_chip_specific *cspec = dd->cspec;
+
+ if (!(dd->flags & QIB_DCA_ENABLED))
+ return;
+ if (cspec->rhdr_cpu[rcd->ctxt] != cpu) {
+ const struct dca_reg_map *rmp;
+
+ cspec->rhdr_cpu[rcd->ctxt] = cpu;
+ rmp = &dca_rcvhdr_reg_map[rcd->ctxt];
+ cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] &= rmp->mask;
+ cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] |=
+ (u64) dca3_get_tag(&dd->pcidev->dev, cpu) << rmp->lsb;
+ qib_devinfo(dd->pcidev,
+ "Ctxt %d cpu %d dca %llx\n", rcd->ctxt, cpu,
+ (long long) cspec->dca_rcvhdr_ctrl[rmp->shadow_inx]);
+ qib_write_kreg(dd, rmp->regno,
+ cspec->dca_rcvhdr_ctrl[rmp->shadow_inx]);
+ cspec->dca_ctrl |= SYM_MASK(DCACtrlA, RcvHdrqDCAEnable);
+ qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
+ }
+}
+
+static void qib_update_sdma_dca(struct qib_pportdata *ppd, int cpu)
+{
+ struct qib_devdata *dd = ppd->dd;
+ struct qib_chip_specific *cspec = dd->cspec;
+ unsigned pidx = ppd->port - 1;
+
+ if (!(dd->flags & QIB_DCA_ENABLED))
+ return;
+ if (cspec->sdma_cpu[pidx] != cpu) {
+ cspec->sdma_cpu[pidx] = cpu;
+ cspec->dca_rcvhdr_ctrl[4] &= ~(ppd->hw_pidx ?
+ SYM_MASK(DCACtrlF, SendDma1DCAOPH) :
+ SYM_MASK(DCACtrlF, SendDma0DCAOPH));
+ cspec->dca_rcvhdr_ctrl[4] |=
+ (u64) dca3_get_tag(&dd->pcidev->dev, cpu) <<
+ (ppd->hw_pidx ?
+ SYM_LSB(DCACtrlF, SendDma1DCAOPH) :
+ SYM_LSB(DCACtrlF, SendDma0DCAOPH));
+ qib_devinfo(dd->pcidev,
+ "sdma %d cpu %d dca %llx\n", ppd->hw_pidx, cpu,
+ (long long) cspec->dca_rcvhdr_ctrl[4]);
+ qib_write_kreg(dd, KREG_IDX(DCACtrlF),
+ cspec->dca_rcvhdr_ctrl[4]);
+ cspec->dca_ctrl |= ppd->hw_pidx ?
+ SYM_MASK(DCACtrlA, SendDMAHead1DCAEnable) :
+ SYM_MASK(DCACtrlA, SendDMAHead0DCAEnable);
+ qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
+ }
+}
+
+static void qib_setup_dca(struct qib_devdata *dd)
+{
+ struct qib_chip_specific *cspec = dd->cspec;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cspec->rhdr_cpu); i++)
+ cspec->rhdr_cpu[i] = -1;
+ for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
+ cspec->sdma_cpu[i] = -1;
+ cspec->dca_rcvhdr_ctrl[0] =
+ (1ULL << SYM_LSB(DCACtrlB, RcvHdrq0DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlB, RcvHdrq1DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlB, RcvHdrq2DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlB, RcvHdrq3DCAXfrCnt));
+ cspec->dca_rcvhdr_ctrl[1] =
+ (1ULL << SYM_LSB(DCACtrlC, RcvHdrq4DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlC, RcvHdrq5DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlC, RcvHdrq6DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlC, RcvHdrq7DCAXfrCnt));
+ cspec->dca_rcvhdr_ctrl[2] =
+ (1ULL << SYM_LSB(DCACtrlD, RcvHdrq8DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlD, RcvHdrq9DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlD, RcvHdrq10DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlD, RcvHdrq11DCAXfrCnt));
+ cspec->dca_rcvhdr_ctrl[3] =
+ (1ULL << SYM_LSB(DCACtrlE, RcvHdrq12DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlE, RcvHdrq13DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlE, RcvHdrq14DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlE, RcvHdrq15DCAXfrCnt));
+ cspec->dca_rcvhdr_ctrl[4] =
+ (1ULL << SYM_LSB(DCACtrlF, RcvHdrq16DCAXfrCnt)) |
+ (1ULL << SYM_LSB(DCACtrlF, RcvHdrq17DCAXfrCnt));
+ for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
+ qib_write_kreg(dd, KREG_IDX(DCACtrlB) + i,
+ cspec->dca_rcvhdr_ctrl[i]);
+ for (i = 0; i < cspec->num_msix_entries; i++)
+ setup_dca_notifier(dd, &cspec->msix_entries[i]);
+}
+
+static void qib_irq_notifier_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
+{
+ struct qib_irq_notify *n =
+ container_of(notify, struct qib_irq_notify, notify);
+ int cpu = cpumask_first(mask);
+
+ if (n->rcv) {
+ struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+ qib_update_rhdrq_dca(rcd, cpu);
+ } else {
+ struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+ qib_update_sdma_dca(ppd, cpu);
+ }
+}
+
+static void qib_irq_notifier_release(struct kref *ref)
+{
+ struct qib_irq_notify *n =
+ container_of(ref, struct qib_irq_notify, notify.kref);
+ struct qib_devdata *dd;
+
+ if (n->rcv) {
+ struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+ dd = rcd->dd;
+ } else {
+ struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+ dd = ppd->dd;
+ }
+ qib_devinfo(dd->pcidev,
+ "release on HCA notify 0x%p n 0x%p\n", ref, n);
+ kfree(n);
+}
+#endif
+
/*
* Disable MSIx interrupt if enabled, call generic MSIx code
* to cleanup, and clear pending MSIx interrupts.
@@ -2575,6 +2837,9 @@ static void qib_7322_nomsix(struct qib_devdata *dd)
dd->cspec->num_msix_entries = 0;
for (i = 0; i < n; i++) {
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ reset_dca_notifier(dd, &dd->cspec->msix_entries[i]);
+#endif
irq_set_affinity_hint(
dd->cspec->msix_entries[i].msix.vector, NULL);
free_cpumask_var(dd->cspec->msix_entries[i].mask);
@@ -2602,6 +2867,15 @@ static void qib_setup_7322_cleanup(struct qib_devdata *dd)
{
int i;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ if (dd->flags & QIB_DCA_ENABLED) {
+ dca_remove_requester(&dd->pcidev->dev);
+ dd->flags &= ~QIB_DCA_ENABLED;
+ dd->cspec->dca_ctrl = 0;
+ qib_write_kreg(dd, KREG_IDX(DCACtrlA), dd->cspec->dca_ctrl);
+ }
+#endif
+
qib_7322_free_irq(dd);
kfree(dd->cspec->cntrs);
kfree(dd->cspec->sendchkenable);
@@ -3068,6 +3342,53 @@ static irqreturn_t sdma_cleanup_intr(int irq, void *data)
return IRQ_HANDLED;
}
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static void reset_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
+{
+ if (!m->dca)
+ return;
+ qib_devinfo(dd->pcidev,
+ "Disabling notifier on HCA %d irq %d\n",
+ dd->unit,
+ m->msix.vector);
+ irq_set_affinity_notifier(
+ m->msix.vector,
+ NULL);
+ m->notifier = NULL;
+}
+
+static void setup_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
+{
+ struct qib_irq_notify *n;
+
+ if (!m->dca)
+ return;
+ n = kzalloc(sizeof(*n), GFP_KERNEL);
+ if (n) {
+ int ret;
+
+ m->notifier = n;
+ n->notify.irq = m->msix.vector;
+ n->notify.notify = qib_irq_notifier_notify;
+ n->notify.release = qib_irq_notifier_release;
+ n->arg = m->arg;
+ n->rcv = m->rcv;
+ qib_devinfo(dd->pcidev,
+ "set notifier irq %d rcv %d notify %p\n",
+ n->notify.irq, n->rcv, &n->notify);
+ ret = irq_set_affinity_notifier(
+ n->notify.irq,
+ &n->notify);
+ if (ret) {
+ m->notifier = NULL;
+ kfree(n);
+ }
+ }
+}
+
+#endif
+
/*
* Set up our chip-specific interrupt handler.
* The interrupt type has already been setup, so
@@ -3149,6 +3470,9 @@ try_intx:
void *arg;
u64 val;
int lsb, reg, sh;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ int dca = 0;
+#endif
dd->cspec->msix_entries[msixnum].
name[sizeof(dd->cspec->msix_entries[msixnum].name) - 1]
@@ -3161,6 +3485,9 @@ try_intx:
arg = dd->pport + irq_table[i].port - 1;
} else
arg = dd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dca = irq_table[i].dca;
+#endif
lsb = irq_table[i].lsb;
handler = irq_table[i].handler;
snprintf(dd->cspec->msix_entries[msixnum].name,
@@ -3178,6 +3505,9 @@ try_intx:
continue;
if (qib_krcvq01_no_msi && ctxt < 2)
continue;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dca = 1;
+#endif
lsb = QIB_I_RCVAVAIL_LSB + ctxt;
handler = qib_7322pintr;
snprintf(dd->cspec->msix_entries[msixnum].name,
@@ -3203,6 +3533,11 @@ try_intx:
goto try_intx;
}
dd->cspec->msix_entries[msixnum].arg = arg;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dd->cspec->msix_entries[msixnum].dca = dca;
+ dd->cspec->msix_entries[msixnum].rcv =
+ handler == qib_7322pintr;
+#endif
if (lsb >= 0) {
reg = lsb / IBA7322_REDIRECT_VEC_PER_REG;
sh = (lsb % IBA7322_REDIRECT_VEC_PER_REG) *
@@ -6452,6 +6787,86 @@ static void qib_sdma_set_7322_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
qib_write_kreg_port(ppd, krp_senddmadesccnt, cnt);
}
+/*
+ * sdma_lock should be acquired before calling this routine
+ */
+static void dump_sdma_7322_state(struct qib_pportdata *ppd)
+{
+ u64 reg, reg1, reg2;
+
+ reg = qib_read_kreg_port(ppd, krp_senddmastatus);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmastatus: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_sendctrl);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA sendctrl: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmabase);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmabase: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmabufmask0);
+ reg1 = qib_read_kreg_port(ppd, krp_senddmabufmask1);
+ reg2 = qib_read_kreg_port(ppd, krp_senddmabufmask2);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmabufmask 0:%llx 1:%llx 2:%llx\n",
+ reg, reg1, reg2);
+
+ /* get bufuse bits, clear them, and print them again if non-zero */
+ reg = qib_read_kreg_port(ppd, krp_senddmabuf_use0);
+ qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg);
+ reg1 = qib_read_kreg_port(ppd, krp_senddmabuf_use1);
+ qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg1);
+ reg2 = qib_read_kreg_port(ppd, krp_senddmabuf_use2);
+ qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg2);
+ /* 0 and 1 should always be zero, so print as short form */
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA current senddmabuf_use 0:%llx 1:%llx 2:%llx\n",
+ reg, reg1, reg2);
+ reg = qib_read_kreg_port(ppd, krp_senddmabuf_use0);
+ reg1 = qib_read_kreg_port(ppd, krp_senddmabuf_use1);
+ reg2 = qib_read_kreg_port(ppd, krp_senddmabuf_use2);
+ /* 0 and 1 should always be zero, so print as short form */
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA cleared senddmabuf_use 0:%llx 1:%llx 2:%llx\n",
+ reg, reg1, reg2);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmatail);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmatail: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmahead);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmahead: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmaheadaddr);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmaheadaddr: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmalengen);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmalengen: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmadesccnt);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmadesccnt: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmaidlecnt);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmaidlecnt: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmaprioritythld);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmapriorityhld: 0x%016llx\n", reg);
+
+ reg = qib_read_kreg_port(ppd, krp_senddmareloadcnt);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA senddmareloadcnt: 0x%016llx\n", reg);
+
+ dump_sdma_state(ppd);
+}
+
static struct sdma_set_state_action sdma_7322_action_table[] = {
[qib_sdma_state_s00_hw_down] = {
.go_s99_running_tofalse = 1,
@@ -6885,6 +7300,9 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
dd->f_sdma_init_early = qib_7322_sdma_init_early;
dd->f_writescratch = writescratch;
dd->f_tempsense_rd = qib_7322_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dd->f_notify_dca = qib_7322_notify_dca;
+#endif
/*
* Do remaining PCIe setup and save PCIe values in dd.
* Any error printing is already done by the init code.
@@ -6921,7 +7339,7 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
actual_cnt -= dd->num_pports;
tabsize = actual_cnt;
- dd->cspec->msix_entries = kmalloc(tabsize *
+ dd->cspec->msix_entries = kzalloc(tabsize *
sizeof(struct qib_msix_entry), GFP_KERNEL);
if (!dd->cspec->msix_entries) {
qib_dev_err(dd, "No memory for MSIx table\n");
@@ -6941,7 +7359,13 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
/* clear diagctrl register, in case diags were running and crashed */
qib_write_kreg(dd, kr_hwdiagctrl, 0);
-
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ if (!dca_add_requester(&pdev->dev)) {
+ qib_devinfo(dd->pcidev, "DCA enabled\n");
+ dd->flags |= QIB_DCA_ENABLED;
+ qib_setup_dca(dd);
+ }
+#endif
goto bail;
bail_cleanup:
@@ -7156,15 +7580,20 @@ static const struct txdds_ent txdds_extra_sdr[TXDDS_EXTRA_SZ] = {
{ 0, 0, 0, 1 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 2 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 2 }, /* QMH7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
- { 0, 0, 0, 11 }, /* QME7342 backplane settings */
{ 0, 0, 0, 3 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 4 }, /* QMH7342 backplane settings */
+ { 0, 1, 4, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 3, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 12 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 14 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 2, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 7 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 6 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 8 }, /* QME7342 backplane settings 1.1 */
};
static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
@@ -7173,15 +7602,20 @@ static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
{ 0, 0, 0, 7 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 8 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 8 }, /* QMH7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
- { 0, 0, 0, 13 }, /* QME7342 backplane settings */
{ 0, 0, 0, 9 }, /* QMH7342 backplane settings */
{ 0, 0, 0, 10 }, /* QMH7342 backplane settings */
+ { 0, 1, 4, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 3, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 12 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 14 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 2, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 7 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 6 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 8 }, /* QME7342 backplane settings 1.1 */
};
static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
@@ -7190,15 +7624,20 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
{ 0, 1, 0, 5 }, /* QMH7342 backplane settings */
{ 0, 1, 0, 6 }, /* QMH7342 backplane settings */
{ 0, 1, 0, 8 }, /* QMH7342 backplane settings */
- { 0, 1, 12, 10 }, /* QME7342 backplane setting */
- { 0, 1, 12, 11 }, /* QME7342 backplane setting */
- { 0, 1, 12, 12 }, /* QME7342 backplane setting */
- { 0, 1, 12, 14 }, /* QME7342 backplane setting */
- { 0, 1, 12, 6 }, /* QME7342 backplane setting */
- { 0, 1, 12, 7 }, /* QME7342 backplane setting */
- { 0, 1, 12, 8 }, /* QME7342 backplane setting */
{ 0, 1, 0, 10 }, /* QMH7342 backplane settings */
{ 0, 1, 0, 12 }, /* QMH7342 backplane settings */
+ { 0, 1, 4, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 3, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 12 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 14 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 2, 15 }, /* QME7342 backplane settings 1.0 */
+ { 0, 1, 0, 11 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 7 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 9 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 6 }, /* QME7342 backplane settings 1.1 */
+ { 0, 1, 0, 8 }, /* QME7342 backplane settings 1.1 */
};
static const struct txdds_ent txdds_extra_mfg[TXDDS_MFG_SZ] = {
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 173f805790da..36e048e0e1d9 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -39,10 +39,17 @@
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/printk.h>
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+#include <linux/dca.h>
+#endif
#include "qib.h"
#include "qib_common.h"
#include "qib_mad.h"
+#ifdef CONFIG_DEBUG_FS
+#include "qib_debugfs.h"
+#include "qib_verbs.h"
+#endif
#undef pr_fmt
#define pr_fmt(fmt) QIB_DRV_NAME ": " fmt
@@ -64,6 +71,11 @@ ushort qib_cfgctxts;
module_param_named(cfgctxts, qib_cfgctxts, ushort, S_IRUGO);
MODULE_PARM_DESC(cfgctxts, "Set max number of contexts to use");
+unsigned qib_numa_aware;
+module_param_named(numa_aware, qib_numa_aware, uint, S_IRUGO);
+MODULE_PARM_DESC(numa_aware,
+ "0 -> PSM allocation close to HCA, 1 -> PSM allocation local to process");
+
/*
* If set, do not write to any regs if avoidable, hack to allow
* check for deranged default register values.
@@ -89,8 +101,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_cq_wq;
-
static void verify_interrupt(unsigned long);
static struct idr qib_unit_table;
@@ -121,6 +131,11 @@ int qib_create_ctxts(struct qib_devdata *dd)
{
unsigned i;
int ret;
+ int local_node_id = pcibus_to_node(dd->pcidev->bus);
+
+ if (local_node_id < 0)
+ local_node_id = numa_node_id();
+ dd->assigned_node_id = local_node_id;
/*
* Allocate full ctxtcnt array, rather than just cfgctxts, because
@@ -143,7 +158,8 @@ int qib_create_ctxts(struct qib_devdata *dd)
continue;
ppd = dd->pport + (i % dd->num_pports);
- rcd = qib_create_ctxtdata(ppd, i);
+
+ rcd = qib_create_ctxtdata(ppd, i, dd->assigned_node_id);
if (!rcd) {
qib_dev_err(dd,
"Unable to allocate ctxtdata for Kernel ctxt, failing\n");
@@ -161,20 +177,33 @@ done:
/*
* Common code for user and kernel context setup.
*/
-struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt)
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt,
+ int node_id)
{
struct qib_devdata *dd = ppd->dd;
struct qib_ctxtdata *rcd;
- rcd = kzalloc(sizeof(*rcd), GFP_KERNEL);
+ rcd = kzalloc_node(sizeof(*rcd), GFP_KERNEL, node_id);
if (rcd) {
INIT_LIST_HEAD(&rcd->qp_wait_list);
+ rcd->node_id = node_id;
rcd->ppd = ppd;
rcd->dd = dd;
rcd->cnt = 1;
rcd->ctxt = ctxt;
dd->rcd[ctxt] = rcd;
-
+#ifdef CONFIG_DEBUG_FS
+ if (ctxt < dd->first_user_ctxt) { /* N/A for PSM contexts */
+ rcd->opstats = kzalloc_node(sizeof(*rcd->opstats),
+ GFP_KERNEL, node_id);
+ if (!rcd->opstats) {
+ kfree(rcd);
+ qib_dev_err(dd,
+ "Unable to allocate per ctxt stats buffer\n");
+ return NULL;
+ }
+ }
+#endif
dd->f_init_ctxt(rcd);
/*
@@ -429,6 +458,7 @@ static int loadtime_init(struct qib_devdata *dd)
dd->intrchk_timer.function = verify_interrupt;
dd->intrchk_timer.data = (unsigned long) dd;
+ ret = qib_cq_init(dd);
done:
return ret;
}
@@ -944,6 +974,10 @@ void qib_free_ctxtdata(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
vfree(rcd->subctxt_uregbase);
vfree(rcd->subctxt_rcvegrbuf);
vfree(rcd->subctxt_rcvhdr_base);
+#ifdef CONFIG_DEBUG_FS
+ kfree(rcd->opstats);
+ rcd->opstats = NULL;
+#endif
kfree(rcd);
}
@@ -1033,7 +1067,6 @@ done:
dd->f_set_armlaunch(dd, 1);
}
-
void qib_free_devdata(struct qib_devdata *dd)
{
unsigned long flags;
@@ -1043,6 +1076,9 @@ void qib_free_devdata(struct qib_devdata *dd)
list_del(&dd->list);
spin_unlock_irqrestore(&qib_devs_lock, flags);
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_ibdev_exit(&dd->verbs_dev);
+#endif
ib_dealloc_device(&dd->verbs_dev.ibdev);
}
@@ -1066,6 +1102,10 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
goto bail;
}
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_ibdev_init(&dd->verbs_dev);
+#endif
+
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&qib_devs_lock, flags);
@@ -1081,6 +1121,9 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
if (ret < 0) {
qib_early_err(&pdev->dev,
"Could not allocate unit ID: error %d\n", -ret);
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_ibdev_exit(&dd->verbs_dev);
+#endif
ib_dealloc_device(&dd->verbs_dev.ibdev);
dd = ERR_PTR(ret);
goto bail;
@@ -1158,6 +1201,35 @@ struct pci_driver qib_driver = {
.err_handler = &qib_pci_err_handler,
};
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static int qib_notify_dca(struct notifier_block *, unsigned long, void *);
+static struct notifier_block dca_notifier = {
+ .notifier_call = qib_notify_dca,
+ .next = NULL,
+ .priority = 0
+};
+
+static int qib_notify_dca_device(struct device *device, void *data)
+{
+ struct qib_devdata *dd = dev_get_drvdata(device);
+ unsigned long event = *(unsigned long *)data;
+
+ return dd->f_notify_dca(dd, event);
+}
+
+static int qib_notify_dca(struct notifier_block *nb, unsigned long event,
+ void *p)
+{
+ int rval;
+
+ rval = driver_for_each_device(&qib_driver.driver, NULL,
+ &event, qib_notify_dca_device);
+ return rval ? NOTIFY_BAD : NOTIFY_DONE;
+}
+
+#endif
+
/*
* Do all the generic driver unit- and chip-independent memory
* allocation and initialization.
@@ -1170,22 +1242,22 @@ static int __init qlogic_ib_init(void)
if (ret)
goto bail;
- qib_cq_wq = create_singlethread_workqueue("qib_cq");
- if (!qib_cq_wq) {
- ret = -ENOMEM;
- goto bail_dev;
- }
-
/*
* These must be called before the driver is registered with
* the PCI subsystem.
*/
idr_init(&qib_unit_table);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dca_register_notify(&dca_notifier);
+#endif
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_init();
+#endif
ret = pci_register_driver(&qib_driver);
if (ret < 0) {
pr_err("Unable to register driver: error %d\n", -ret);
- goto bail_unit;
+ goto bail_dev;
}
/* not fatal if it doesn't work */
@@ -1193,10 +1265,14 @@ static int __init qlogic_ib_init(void)
pr_err("Unable to register ipathfs\n");
goto bail; /* all OK */
-bail_unit:
- idr_destroy(&qib_unit_table);
- destroy_workqueue(qib_cq_wq);
bail_dev:
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dca_unregister_notify(&dca_notifier);
+#endif
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_exit();
+#endif
+ idr_destroy(&qib_unit_table);
qib_dev_cleanup();
bail:
return ret;
@@ -1217,9 +1293,13 @@ static void __exit qlogic_ib_cleanup(void)
"Unable to cleanup counter filesystem: error %d\n",
-ret);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+ dca_unregister_notify(&dca_notifier);
+#endif
pci_unregister_driver(&qib_driver);
-
- destroy_workqueue(qib_cq_wq);
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_exit();
+#endif
qib_cpulist_count = 0;
kfree(qib_cpulist);
@@ -1270,7 +1350,7 @@ static void cleanup_device_data(struct qib_devdata *dd)
if (dd->pageshadow) {
struct page **tmpp = dd->pageshadow;
dma_addr_t *tmpd = dd->physshadow;
- int i, cnt = 0;
+ int i;
for (ctxt = 0; ctxt < dd->cfgctxts; ctxt++) {
int ctxt_tidbase = ctxt * dd->rcvtidcnt;
@@ -1283,13 +1363,13 @@ static void cleanup_device_data(struct qib_devdata *dd)
PAGE_SIZE, PCI_DMA_FROMDEVICE);
qib_release_user_pages(&tmpp[i], 1);
tmpp[i] = NULL;
- cnt++;
}
}
- tmpp = dd->pageshadow;
dd->pageshadow = NULL;
vfree(tmpp);
+ dd->physshadow = NULL;
+ vfree(tmpd);
}
/*
@@ -1311,6 +1391,7 @@ static void cleanup_device_data(struct qib_devdata *dd)
}
kfree(tmp);
kfree(dd->boardname);
+ qib_cq_exit(dd);
}
/*
@@ -1483,6 +1564,7 @@ static void qib_remove_one(struct pci_dev *pdev)
int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
{
unsigned amt;
+ int old_node_id;
if (!rcd->rcvhdrq) {
dma_addr_t phys_hdrqtail;
@@ -1492,9 +1574,13 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
sizeof(u32), PAGE_SIZE);
gfp_flags = (rcd->ctxt >= dd->first_user_ctxt) ?
GFP_USER : GFP_KERNEL;
+
+ old_node_id = dev_to_node(&dd->pcidev->dev);
+ set_dev_node(&dd->pcidev->dev, rcd->node_id);
rcd->rcvhdrq = dma_alloc_coherent(
&dd->pcidev->dev, amt, &rcd->rcvhdrq_phys,
gfp_flags | __GFP_COMP);
+ set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvhdrq) {
qib_dev_err(dd,
@@ -1510,9 +1596,11 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
}
if (!(dd->flags & QIB_NODMA_RTAIL)) {
+ set_dev_node(&dd->pcidev->dev, rcd->node_id);
rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(
&dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail,
gfp_flags);
+ set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvhdrtail_kvaddr)
goto bail_free;
rcd->rcvhdrqtailaddr_phys = phys_hdrqtail;
@@ -1556,6 +1644,7 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
size_t size;
gfp_t gfp_flags;
+ int old_node_id;
/*
* GFP_USER, but without GFP_FS, so buffer cache can be
@@ -1574,25 +1663,29 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
size = rcd->rcvegrbuf_size;
if (!rcd->rcvegrbuf) {
rcd->rcvegrbuf =
- kzalloc(chunk * sizeof(rcd->rcvegrbuf[0]),
- GFP_KERNEL);
+ kzalloc_node(chunk * sizeof(rcd->rcvegrbuf[0]),
+ GFP_KERNEL, rcd->node_id);
if (!rcd->rcvegrbuf)
goto bail;
}
if (!rcd->rcvegrbuf_phys) {
rcd->rcvegrbuf_phys =
- kmalloc(chunk * sizeof(rcd->rcvegrbuf_phys[0]),
- GFP_KERNEL);
+ kmalloc_node(chunk * sizeof(rcd->rcvegrbuf_phys[0]),
+ GFP_KERNEL, rcd->node_id);
if (!rcd->rcvegrbuf_phys)
goto bail_rcvegrbuf;
}
for (e = 0; e < rcd->rcvegrbuf_chunks; e++) {
if (rcd->rcvegrbuf[e])
continue;
+
+ old_node_id = dev_to_node(&dd->pcidev->dev);
+ set_dev_node(&dd->pcidev->dev, rcd->node_id);
rcd->rcvegrbuf[e] =
dma_alloc_coherent(&dd->pcidev->dev, size,
&rcd->rcvegrbuf_phys[e],
gfp_flags);
+ set_dev_node(&dd->pcidev->dev, old_node_id);
if (!rcd->rcvegrbuf[e])
goto bail_rcvegrbuf_phys;
}
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index a6a2cc2ba260..3cca55b51e54 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. * All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -35,6 +35,9 @@
#include <linux/err.h>
#include <linux/vmalloc.h>
#include <linux/jhash.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+#endif
#include "qib.h"
@@ -222,8 +225,8 @@ static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
unsigned long flags;
unsigned n = qpn_hash(dev, qp->ibqp.qp_num);
- spin_lock_irqsave(&dev->qpt_lock, flags);
atomic_inc(&qp->refcount);
+ spin_lock_irqsave(&dev->qpt_lock, flags);
if (qp->ibqp.qp_num == 0)
rcu_assign_pointer(ibp->qp0, qp);
@@ -235,7 +238,6 @@ static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
}
spin_unlock_irqrestore(&dev->qpt_lock, flags);
- synchronize_rcu();
}
/*
@@ -247,36 +249,39 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
unsigned n = qpn_hash(dev, qp->ibqp.qp_num);
unsigned long flags;
+ int removed = 1;
spin_lock_irqsave(&dev->qpt_lock, flags);
if (rcu_dereference_protected(ibp->qp0,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- atomic_dec(&qp->refcount);
rcu_assign_pointer(ibp->qp0, NULL);
} else if (rcu_dereference_protected(ibp->qp1,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- atomic_dec(&qp->refcount);
rcu_assign_pointer(ibp->qp1, NULL);
} else {
struct qib_qp *q;
struct qib_qp __rcu **qpp;
+ removed = 0;
qpp = &dev->qp_table[n];
for (; (q = rcu_dereference_protected(*qpp,
lockdep_is_held(&dev->qpt_lock))) != NULL;
qpp = &q->next)
if (q == qp) {
- atomic_dec(&qp->refcount);
rcu_assign_pointer(*qpp,
rcu_dereference_protected(qp->next,
lockdep_is_held(&dev->qpt_lock)));
+ removed = 1;
break;
}
}
spin_unlock_irqrestore(&dev->qpt_lock, flags);
- synchronize_rcu();
+ if (removed) {
+ synchronize_rcu();
+ atomic_dec(&qp->refcount);
+ }
}
/**
@@ -334,26 +339,25 @@ struct qib_qp *qib_lookup_qpn(struct qib_ibport *ibp, u32 qpn)
{
struct qib_qp *qp = NULL;
+ rcu_read_lock();
if (unlikely(qpn <= 1)) {
- rcu_read_lock();
if (qpn == 0)
qp = rcu_dereference(ibp->qp0);
else
qp = rcu_dereference(ibp->qp1);
+ if (qp)
+ atomic_inc(&qp->refcount);
} else {
struct qib_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev;
unsigned n = qpn_hash(dev, qpn);
- rcu_read_lock();
for (qp = rcu_dereference(dev->qp_table[n]); qp;
qp = rcu_dereference(qp->next))
- if (qp->ibqp.qp_num == qpn)
+ if (qp->ibqp.qp_num == qpn) {
+ atomic_inc(&qp->refcount);
break;
+ }
}
- if (qp)
- if (unlikely(!atomic_inc_not_zero(&qp->refcount)))
- qp = NULL;
-
rcu_read_unlock();
return qp;
}
@@ -1286,3 +1290,94 @@ void qib_get_credit(struct qib_qp *qp, u32 aeth)
}
}
}
+
+#ifdef CONFIG_DEBUG_FS
+
+struct qib_qp_iter {
+ struct qib_ibdev *dev;
+ struct qib_qp *qp;
+ int n;
+};
+
+struct qib_qp_iter *qib_qp_iter_init(struct qib_ibdev *dev)
+{
+ struct qib_qp_iter *iter;
+
+ iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+ if (!iter)
+ return NULL;
+
+ iter->dev = dev;
+ if (qib_qp_iter_next(iter)) {
+ kfree(iter);
+ return NULL;
+ }
+
+ return iter;
+}
+
+int qib_qp_iter_next(struct qib_qp_iter *iter)
+{
+ struct qib_ibdev *dev = iter->dev;
+ int n = iter->n;
+ int ret = 1;
+ struct qib_qp *pqp = iter->qp;
+ struct qib_qp *qp;
+
+ rcu_read_lock();
+ for (; n < dev->qp_table_size; n++) {
+ if (pqp)
+ qp = rcu_dereference(pqp->next);
+ else
+ qp = rcu_dereference(dev->qp_table[n]);
+ pqp = qp;
+ if (qp) {
+ if (iter->qp)
+ atomic_dec(&iter->qp->refcount);
+ atomic_inc(&qp->refcount);
+ rcu_read_unlock();
+ iter->qp = qp;
+ iter->n = n;
+ return 0;
+ }
+ }
+ rcu_read_unlock();
+ if (iter->qp)
+ atomic_dec(&iter->qp->refcount);
+ return ret;
+}
+
+static const char * const qp_type_str[] = {
+ "SMI", "GSI", "RC", "UC", "UD",
+};
+
+void qib_qp_iter_print(struct seq_file *s, struct qib_qp_iter *iter)
+{
+ struct qib_swqe *wqe;
+ struct qib_qp *qp = iter->qp;
+
+ wqe = get_swqe_ptr(qp, qp->s_last);
+ seq_printf(s,
+ "N %d QP%u %s %u %u %u f=%x %u %u %u %u %u PSN %x %x %x %x %x (%u %u %u %u %u %u) QP%u LID %x\n",
+ iter->n,
+ qp->ibqp.qp_num,
+ qp_type_str[qp->ibqp.qp_type],
+ qp->state,
+ wqe->wr.opcode,
+ qp->s_hdrwords,
+ qp->s_flags,
+ atomic_read(&qp->s_dma_busy),
+ !list_empty(&qp->iowait),
+ qp->timeout,
+ wqe->ssn,
+ qp->s_lsn,
+ qp->s_last_psn,
+ qp->s_psn, qp->s_next_psn,
+ qp->s_sending_psn, qp->s_sending_hpsn,
+ qp->s_last, qp->s_acked, qp->s_cur,
+ qp->s_tail, qp->s_head, qp->s_size,
+ qp->remote_qpn,
+ qp->remote_ah_attr.dlid);
+}
+
+#endif
diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c
index 3fc514431212..32162d355370 100644
--- a/drivers/infiniband/hw/qib/qib_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_sdma.c
@@ -708,6 +708,62 @@ unlock:
return ret;
}
+/*
+ * sdma_lock should be acquired before calling this routine
+ */
+void dump_sdma_state(struct qib_pportdata *ppd)
+{
+ struct qib_sdma_desc *descq;
+ struct qib_sdma_txreq *txp, *txpnext;
+ __le64 *descqp;
+ u64 desc[2];
+ dma_addr_t addr;
+ u16 gen, dwlen, dwoffset;
+ u16 head, tail, cnt;
+
+ head = ppd->sdma_descq_head;
+ tail = ppd->sdma_descq_tail;
+ cnt = qib_sdma_descq_freecnt(ppd);
+ descq = ppd->sdma_descq;
+
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA ppd->sdma_descq_head: %u\n", head);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA ppd->sdma_descq_tail: %u\n", tail);
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA sdma_descq_freecnt: %u\n", cnt);
+
+ /* print info for each entry in the descriptor queue */
+ while (head != tail) {
+ char flags[6] = { 'x', 'x', 'x', 'x', 'x', 0 };
+
+ descqp = &descq[head].qw[0];
+ desc[0] = le64_to_cpu(descqp[0]);
+ desc[1] = le64_to_cpu(descqp[1]);
+ flags[0] = (desc[0] & 1<<15) ? 'I' : '-';
+ flags[1] = (desc[0] & 1<<14) ? 'L' : 'S';
+ flags[2] = (desc[0] & 1<<13) ? 'H' : '-';
+ flags[3] = (desc[0] & 1<<12) ? 'F' : '-';
+ flags[4] = (desc[0] & 1<<11) ? 'L' : '-';
+ addr = (desc[1] << 32) | ((desc[0] >> 32) & 0xfffffffcULL);
+ gen = (desc[0] >> 30) & 3ULL;
+ dwlen = (desc[0] >> 14) & (0x7ffULL << 2);
+ dwoffset = (desc[0] & 0x7ffULL) << 2;
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes offset:%u bytes\n",
+ head, flags, addr, gen, dwlen, dwoffset);
+ if (++head == ppd->sdma_descq_cnt)
+ head = 0;
+ }
+
+ /* print dma descriptor indices from the TX requests */
+ list_for_each_entry_safe(txp, txpnext, &ppd->sdma_activelist,
+ list)
+ qib_dev_porterr(ppd->dd, ppd->port,
+ "SDMA txp->start_idx: %u txp->next_descq_idx: %u\n",
+ txp->start_idx, txp->next_descq_idx);
+}
+
void qib_sdma_process_event(struct qib_pportdata *ppd,
enum qib_sdma_events event)
{
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 904c384aa361..092b0bb1bb78 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -645,9 +645,11 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
} else
goto drop;
- opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
- ibp->opstats[opcode & 0x7f].n_bytes += tlen;
- ibp->opstats[opcode & 0x7f].n_packets++;
+ opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f;
+#ifdef CONFIG_DEBUG_FS
+ rcd->opstats->stats[opcode].n_bytes += tlen;
+ rcd->opstats->stats[opcode].n_packets++;
+#endif
/* Get the destination QP number. */
qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index aff8b2c17886..012e2c7575ad 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -41,6 +41,7 @@
#include <linux/interrupt.h>
#include <linux/kref.h>
#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/completion.h>
#include <rdma/ib_pack.h>
#include <rdma/ib_user_verbs.h>
@@ -267,7 +268,8 @@ struct qib_cq_wc {
*/
struct qib_cq {
struct ib_cq ibcq;
- struct work_struct comptask;
+ struct kthread_work comptask;
+ struct qib_devdata *dd;
spinlock_t lock; /* protect changes in this struct */
u8 notify;
u8 triggered;
@@ -658,6 +660,10 @@ struct qib_opcode_stats {
u64 n_bytes; /* total number of bytes */
};
+struct qib_opcode_stats_perctx {
+ struct qib_opcode_stats stats[128];
+};
+
struct qib_ibport {
struct qib_qp __rcu *qp0;
struct qib_qp __rcu *qp1;
@@ -724,7 +730,6 @@ struct qib_ibport {
u8 vl_high_limit;
u8 sl_to_vl[16];
- struct qib_opcode_stats opstats[128];
};
@@ -768,6 +773,10 @@ struct qib_ibdev {
spinlock_t n_srqs_lock;
u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
spinlock_t n_mcast_grps_lock;
+#ifdef CONFIG_DEBUG_FS
+ /* per HCA debugfs */
+ struct dentry *qib_ibdev_dbg;
+#endif
};
struct qib_verbs_counters {
@@ -832,8 +841,6 @@ static inline int qib_send_ok(struct qib_qp *qp)
!(qp->s_flags & QIB_S_ANY_WAIT_SEND));
}
-extern struct workqueue_struct *qib_cq_wq;
-
/*
* This must be called with s_lock held.
*/
@@ -910,6 +917,18 @@ void qib_init_qpn_table(struct qib_devdata *dd, struct qib_qpn_table *qpt);
void qib_free_qpn_table(struct qib_qpn_table *qpt);
+#ifdef CONFIG_DEBUG_FS
+
+struct qib_qp_iter;
+
+struct qib_qp_iter *qib_qp_iter_init(struct qib_ibdev *dev);
+
+int qib_qp_iter_next(struct qib_qp_iter *iter);
+
+void qib_qp_iter_print(struct seq_file *s, struct qib_qp_iter *iter);
+
+#endif
+
void qib_get_credit(struct qib_qp *qp, u32 aeth);
unsigned qib_pkt_delay(u32 plen, u8 snd_mult, u8 rcv_mult);
@@ -972,6 +991,10 @@ int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
int qib_destroy_srq(struct ib_srq *ibsrq);
+int qib_cq_init(struct qib_devdata *dd);
+
+void qib_cq_exit(struct qib_devdata *dd);
+
void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int sig);
int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 2693129055c1..3f62041222f2 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -388,6 +388,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
init_waitqueue_head(&isert_conn->conn_wait_comp_err);
kref_init(&isert_conn->conn_kref);
kref_get(&isert_conn->conn_kref);
+ mutex_init(&isert_conn->conn_mutex);
cma_id->context = isert_conn;
isert_conn->conn_cm_id = cma_id;
@@ -540,15 +541,32 @@ isert_disconnect_work(struct work_struct *work)
struct isert_conn, conn_logout_work);
pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-
+ mutex_lock(&isert_conn->conn_mutex);
isert_conn->state = ISER_CONN_DOWN;
if (isert_conn->post_recv_buf_count == 0 &&
atomic_read(&isert_conn->post_send_buf_count) == 0) {
pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
- wake_up(&isert_conn->conn_wait);
+ mutex_unlock(&isert_conn->conn_mutex);
+ goto wake_up;
+ }
+ if (!isert_conn->conn_cm_id) {
+ mutex_unlock(&isert_conn->conn_mutex);
+ isert_put_conn(isert_conn);
+ return;
}
+ if (!isert_conn->logout_posted) {
+ pr_debug("Calling rdma_disconnect for !logout_posted from"
+ " isert_disconnect_work\n");
+ rdma_disconnect(isert_conn->conn_cm_id);
+ mutex_unlock(&isert_conn->conn_mutex);
+ iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+ goto wake_up;
+ }
+ mutex_unlock(&isert_conn->conn_mutex);
+wake_up:
+ wake_up(&isert_conn->conn_wait);
isert_put_conn(isert_conn);
}
@@ -934,16 +952,11 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
}
sequence_cmd:
- rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+ rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
if (!rc && dump_payload == false && unsol_data)
iscsit_set_unsoliticed_dataout(cmd);
- if (rc == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, (unsigned char *)hdr, cmd);
-
return 0;
}
@@ -1001,17 +1014,71 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
}
static int
+isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
+ int rc;
+
+ rc = iscsit_setup_nop_out(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ /*
+ * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload
+ */
+
+ return iscsit_process_nop_out(conn, cmd, hdr);
+}
+
+static int
+isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct iser_rx_desc *rx_desc, struct iscsi_text *hdr)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int rc;
+ unsigned char *text_in;
+
+ rc = iscsit_setup_text_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+
+ text_in = kzalloc(payload_length, GFP_KERNEL);
+ if (!text_in) {
+ pr_err("Unable to allocate text_in of payload_length: %u\n",
+ payload_length);
+ return -ENOMEM;
+ }
+ cmd->text_in_ptr = text_in;
+
+ memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
+
+ return iscsit_process_text_cmd(conn, cmd, hdr);
+}
+
+static int
isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
uint32_t read_stag, uint64_t read_va,
uint32_t write_stag, uint64_t write_va)
{
struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_session *sess = conn->sess;
struct iscsi_cmd *cmd;
struct isert_cmd *isert_cmd;
int ret = -EINVAL;
u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
+ if (sess->sess_ops->SessionType &&
+ (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) {
+ pr_err("Got illegal opcode: 0x%02x in SessionType=Discovery,"
+ " ignoring\n", opcode);
+ return 0;
+ }
+
switch (opcode) {
case ISCSI_OP_SCSI_CMD:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
@@ -1032,7 +1099,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
if (!cmd)
break;
- ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ ret = isert_handle_nop_out(isert_conn, isert_cmd,
+ rx_desc, (unsigned char *)hdr);
break;
case ISCSI_OP_SCSI_DATA_OUT:
ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
@@ -1057,6 +1126,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
SECONDS_FOR_LOGOUT_COMP *
HZ);
break;
+ case ISCSI_OP_TEXT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ ret = isert_handle_text_cmd(isert_conn, isert_cmd,
+ rx_desc, (struct iscsi_text *)hdr);
+ break;
default:
pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
dump_stack();
@@ -1184,14 +1262,12 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
{
struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
struct isert_conn *isert_conn = isert_cmd->conn;
- struct iscsi_conn *conn;
+ struct iscsi_conn *conn = isert_conn->conn;
pr_debug("Entering isert_put_cmd: %p\n", isert_cmd);
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
- conn = isert_conn->conn;
-
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del(&cmd->i_conn_node);
@@ -1201,16 +1277,19 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
iscsit_stop_dataout_timer(cmd);
isert_unmap_cmd(isert_cmd, isert_conn);
- /*
- * Fall-through
- */
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+ break;
case ISCSI_OP_SCSI_TMFUNC:
+ spin_lock_bh(&conn->cmd_lock);
+ if (!list_empty(&cmd->i_conn_node))
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
case ISCSI_OP_REJECT:
case ISCSI_OP_NOOP_OUT:
- conn = isert_conn->conn;
-
+ case ISCSI_OP_TEXT:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del(&cmd->i_conn_node);
@@ -1222,6 +1301,9 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
* associated cmd->se_cmd needs to be released.
*/
if (cmd->se_cmd.se_tfo != NULL) {
+ pr_debug("Calling transport_generic_free_cmd from"
+ " isert_put_cmd for 0x%02x\n",
+ cmd->iscsi_opcode);
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
}
@@ -1249,11 +1331,11 @@ static void
isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd,
struct ib_device *ib_dev)
{
- if (isert_cmd->sense_buf_dma != 0) {
- pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n");
- ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma,
- isert_cmd->sense_buf_len, DMA_TO_DEVICE);
- isert_cmd->sense_buf_dma = 0;
+ if (isert_cmd->pdu_buf_dma != 0) {
+ pr_debug("Calling ib_dma_unmap_single for isert_cmd->pdu_buf_dma\n");
+ ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma,
+ isert_cmd->pdu_buf_len, DMA_TO_DEVICE);
+ isert_cmd->pdu_buf_dma = 0;
}
isert_unmap_tx_desc(tx_desc, ib_dev);
@@ -1318,8 +1400,8 @@ isert_do_control_comp(struct work_struct *work)
atomic_dec(&isert_conn->post_send_buf_count);
cmd->i_state = ISTATE_SENT_STATUS;
- complete(&cmd->reject_comp);
isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ break;
case ISTATE_SEND_LOGOUTRSP:
pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
/*
@@ -1329,6 +1411,11 @@ isert_do_control_comp(struct work_struct *work)
isert_conn->logout_posted = true;
iscsit_logout_post_handler(cmd, cmd->conn);
break;
+ case ISTATE_SEND_TEXTRSP:
+ atomic_dec(&isert_conn->post_send_buf_count);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ break;
default:
pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state);
dump_stack();
@@ -1345,7 +1432,9 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
- cmd->i_state == ISTATE_SEND_LOGOUTRSP) {
+ cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
+ cmd->i_state == ISTATE_SEND_REJECT ||
+ cmd->i_state == ISTATE_SEND_TEXTRSP) {
isert_unmap_tx_desc(tx_desc, ib_dev);
INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
@@ -1419,7 +1508,11 @@ isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
pr_debug("Calling wake_up from isert_cq_comp_err\n");
- isert_conn->state = ISER_CONN_TERMINATING;
+ mutex_lock(&isert_conn->conn_mutex);
+ if (isert_conn->state != ISER_CONN_DOWN)
+ isert_conn->state = ISER_CONN_TERMINATING;
+ mutex_unlock(&isert_conn->conn_mutex);
+
wake_up(&isert_conn->conn_wait_comp_err);
}
}
@@ -1445,6 +1538,7 @@ isert_cq_tx_work(struct work_struct *work)
} else {
pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
pr_debug("TX wc.status: 0x%08x\n", wc.status);
+ pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
atomic_dec(&isert_conn->post_send_buf_count);
isert_cq_comp_err(tx_desc, isert_conn);
}
@@ -1484,9 +1578,11 @@ isert_cq_rx_work(struct work_struct *work)
isert_rx_completion(rx_desc, isert_conn, xfer_len);
} else {
pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
- if (wc.status != IB_WC_WR_FLUSH_ERR)
+ if (wc.status != IB_WC_WR_FLUSH_ERR) {
pr_debug("RX wc.status: 0x%08x\n", wc.status);
-
+ pr_debug("RX wc.vendor_err: 0x%08x\n",
+ wc.vendor_err);
+ }
isert_conn->post_recv_buf_count--;
isert_cq_comp_err(NULL, isert_conn);
}
@@ -1543,7 +1639,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
(cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
- u32 padding, sense_len;
+ u32 padding, pdu_len;
put_unaligned_be16(cmd->se_cmd.scsi_sense_length,
cmd->sense_buffer);
@@ -1551,15 +1647,15 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
padding = -(cmd->se_cmd.scsi_sense_length) & 3;
hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
- sense_len = cmd->se_cmd.scsi_sense_length + padding;
+ pdu_len = cmd->se_cmd.scsi_sense_length + padding;
- isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev,
- (void *)cmd->sense_buffer, sense_len,
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->sense_buffer, pdu_len,
DMA_TO_DEVICE);
- isert_cmd->sense_buf_len = sense_len;
- tx_dsg->addr = isert_cmd->sense_buf_dma;
- tx_dsg->length = sense_len;
+ isert_cmd->pdu_buf_len = pdu_len;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = pdu_len;
tx_dsg->lkey = isert_conn->conn_mr->lkey;
isert_cmd->tx_desc.num_sge = 2;
}
@@ -1637,11 +1733,25 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
struct isert_cmd, iscsi_cmd);
struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ struct iscsi_reject *hdr =
+ (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header;
isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
- iscsit_build_reject(cmd, conn, (struct iscsi_reject *)
- &isert_cmd->tx_desc.iscsi_header);
+ iscsit_build_reject(cmd, conn, hdr);
isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ hton24(hdr->dlength, ISCSI_HDR_LEN);
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->buf_ptr, ISCSI_HDR_LEN,
+ DMA_TO_DEVICE);
+ isert_cmd->pdu_buf_len = ISCSI_HDR_LEN;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = ISCSI_HDR_LEN;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+
isert_init_send_wr(isert_cmd, send_wr);
pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
@@ -1650,6 +1760,47 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
}
static int
+isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+ struct iscsi_text_rsp *hdr =
+ (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
+ u32 txt_rsp_len;
+ int rc;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ rc = iscsit_build_text_rsp(cmd, conn, hdr);
+ if (rc < 0)
+ return rc;
+
+ txt_rsp_len = rc;
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ if (txt_rsp_len) {
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ void *txt_rsp_buf = cmd->buf_ptr;
+
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE);
+
+ isert_cmd->pdu_buf_len = txt_rsp_len;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = txt_rsp_len;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+ }
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting Text Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
u32 data_left, u32 offset)
@@ -1947,6 +2098,9 @@ isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
case ISTATE_SEND_REJECT:
ret = isert_put_reject(cmd, conn);
break;
+ case ISTATE_SEND_TEXTRSP:
+ ret = isert_put_text_rsp(cmd, conn);
+ break;
case ISTATE_SEND_STATUS:
/*
* Special case for sending non GOOD SCSI status from TX thread
@@ -2175,6 +2329,17 @@ isert_free_np(struct iscsi_np *np)
kfree(isert_np);
}
+static int isert_check_state(struct isert_conn *isert_conn, int state)
+{
+ int ret;
+
+ mutex_lock(&isert_conn->conn_mutex);
+ ret = (isert_conn->state == state);
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ return ret;
+}
+
static void isert_free_conn(struct iscsi_conn *conn)
{
struct isert_conn *isert_conn = conn->context;
@@ -2184,26 +2349,43 @@ static void isert_free_conn(struct iscsi_conn *conn)
* Decrement post_send_buf_count for special case when called
* from isert_do_control_comp() -> iscsit_logout_post_handler()
*/
+ mutex_lock(&isert_conn->conn_mutex);
if (isert_conn->logout_posted)
atomic_dec(&isert_conn->post_send_buf_count);
- if (isert_conn->conn_cm_id)
+ if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
+ pr_debug("Calling rdma_disconnect from isert_free_conn\n");
rdma_disconnect(isert_conn->conn_cm_id);
+ }
/*
* Only wait for conn_wait_comp_err if the isert_conn made it
* into full feature phase..
*/
- if (isert_conn->state > ISER_CONN_INIT) {
+ if (isert_conn->state == ISER_CONN_UP) {
pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
isert_conn->state);
+ mutex_unlock(&isert_conn->conn_mutex);
+
wait_event(isert_conn->conn_wait_comp_err,
- isert_conn->state == ISER_CONN_TERMINATING);
- pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n");
+ (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
+
+ wait_event(isert_conn->conn_wait,
+ (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+
+ isert_put_conn(isert_conn);
+ return;
+ }
+ if (isert_conn->state == ISER_CONN_INIT) {
+ mutex_unlock(&isert_conn->conn_mutex);
+ isert_put_conn(isert_conn);
+ return;
}
+ pr_debug("isert_free_conn: wait_event conn_wait %d\n",
+ isert_conn->state);
+ mutex_unlock(&isert_conn->conn_mutex);
- pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state);
- wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN);
- pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n");
+ wait_event(isert_conn->conn_wait,
+ (isert_check_state(isert_conn, ISER_CONN_DOWN)));
isert_put_conn(isert_conn);
}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index b104f4c2cd38..191117b5b508 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -61,8 +61,8 @@ struct isert_cmd {
uint32_t write_stag;
uint64_t read_va;
uint64_t write_va;
- u64 sense_buf_dma;
- u32 sense_buf_len;
+ u64 pdu_buf_dma;
+ u32 pdu_buf_len;
u32 read_va_off;
u32 write_va_off;
u32 rdma_wr_num;
@@ -102,6 +102,7 @@ struct isert_conn {
struct ib_qp *conn_qp;
struct isert_device *conn_device;
struct work_struct conn_logout_work;
+ struct mutex conn_mutex;
wait_queue_head_t conn_wait;
wait_queue_head_t conn_wait_comp_err;
struct kref conn_kref;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 7ccf3284dda3..f93baf8254c4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -53,8 +53,8 @@
#define DRV_NAME "ib_srp"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "0.2"
-#define DRV_RELDATE "November 1, 2005"
+#define DRV_VERSION "1.0"
+#define DRV_RELDATE "July 1, 2013"
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator "
@@ -231,14 +231,16 @@ static int srp_create_target_ib(struct srp_target_port *target)
return -ENOMEM;
recv_cq = ib_create_cq(target->srp_host->srp_dev->dev,
- srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0);
+ srp_recv_completion, NULL, target, SRP_RQ_SIZE,
+ target->comp_vector);
if (IS_ERR(recv_cq)) {
ret = PTR_ERR(recv_cq);
goto err;
}
send_cq = ib_create_cq(target->srp_host->srp_dev->dev,
- srp_send_completion, NULL, target, SRP_SQ_SIZE, 0);
+ srp_send_completion, NULL, target, SRP_SQ_SIZE,
+ target->comp_vector);
if (IS_ERR(send_cq)) {
ret = PTR_ERR(send_cq);
goto err_recv_cq;
@@ -542,11 +544,11 @@ static void srp_remove_work(struct work_struct *work)
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
+ srp_remove_target(target);
+
spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
spin_unlock(&target->srp_host->target_lock);
-
- srp_remove_target(target);
}
static void srp_rport_delete(struct srp_rport *rport)
@@ -1744,18 +1746,24 @@ static int srp_abort(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
+ int ret;
shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
if (!req || !srp_claim_req(target, req, scmnd))
return FAILED;
- srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
- SRP_TSK_ABORT_TASK);
+ if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+ SRP_TSK_ABORT_TASK) == 0)
+ ret = SUCCESS;
+ else if (target->transport_offline)
+ ret = FAST_IO_FAIL;
+ else
+ ret = FAILED;
srp_free_req(target, req, scmnd, 0);
scmnd->result = DID_ABORT << 16;
scmnd->scsi_done(scmnd);
- return SUCCESS;
+ return ret;
}
static int srp_reset_device(struct scsi_cmnd *scmnd)
@@ -1891,6 +1899,14 @@ static ssize_t show_local_ib_device(struct device *dev,
return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
}
+static ssize_t show_comp_vector(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+ return sprintf(buf, "%d\n", target->comp_vector);
+}
+
static ssize_t show_cmd_sg_entries(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1917,6 +1933,7 @@ static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
+static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL);
static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL);
static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL);
@@ -1931,6 +1948,7 @@ static struct device_attribute *srp_host_attrs[] = {
&dev_attr_zero_req_lim,
&dev_attr_local_ib_port,
&dev_attr_local_ib_device,
+ &dev_attr_comp_vector,
&dev_attr_cmd_sg_entries,
&dev_attr_allow_ext_sg,
NULL
@@ -1946,6 +1964,7 @@ static struct scsi_host_template srp_template = {
.eh_abort_handler = srp_abort,
.eh_device_reset_handler = srp_reset_device,
.eh_host_reset_handler = srp_reset_host,
+ .skip_settle_delay = true,
.sg_tablesize = SRP_DEF_SG_TABLESIZE,
.can_queue = SRP_CMD_SQ_SIZE,
.this_id = -1,
@@ -2001,6 +2020,36 @@ static struct class srp_class = {
.dev_release = srp_release_dev
};
+/**
+ * srp_conn_unique() - check whether the connection to a target is unique
+ */
+static bool srp_conn_unique(struct srp_host *host,
+ struct srp_target_port *target)
+{
+ struct srp_target_port *t;
+ bool ret = false;
+
+ if (target->state == SRP_TARGET_REMOVED)
+ goto out;
+
+ ret = true;
+
+ spin_lock(&host->target_lock);
+ list_for_each_entry(t, &host->target_list, list) {
+ if (t != target &&
+ target->id_ext == t->id_ext &&
+ target->ioc_guid == t->ioc_guid &&
+ target->initiator_ext == t->initiator_ext) {
+ ret = false;
+ break;
+ }
+ }
+ spin_unlock(&host->target_lock);
+
+out:
+ return ret;
+}
+
/*
* Target ports are added by writing
*
@@ -2023,6 +2072,7 @@ enum {
SRP_OPT_CMD_SG_ENTRIES = 1 << 9,
SRP_OPT_ALLOW_EXT_SG = 1 << 10,
SRP_OPT_SG_TABLESIZE = 1 << 11,
+ SRP_OPT_COMP_VECTOR = 1 << 12,
SRP_OPT_ALL = (SRP_OPT_ID_EXT |
SRP_OPT_IOC_GUID |
SRP_OPT_DGID |
@@ -2043,6 +2093,7 @@ static const match_table_t srp_opt_tokens = {
{ SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" },
{ SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" },
{ SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" },
+ { SRP_OPT_COMP_VECTOR, "comp_vector=%u" },
{ SRP_OPT_ERR, NULL }
};
@@ -2198,6 +2249,14 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
target->sg_tablesize = token;
break;
+ case SRP_OPT_COMP_VECTOR:
+ if (match_int(args, &token) || token < 0) {
+ pr_warn("bad comp_vector parameter '%s'\n", p);
+ goto out;
+ }
+ target->comp_vector = token;
+ break;
+
default:
pr_warn("unknown parameter or missing value '%s' in target creation request\n",
p);
@@ -2257,6 +2316,16 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto err;
+ if (!srp_conn_unique(target->srp_host, target)) {
+ shost_printk(KERN_INFO, target->scsi_host,
+ PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
+ be64_to_cpu(target->id_ext),
+ be64_to_cpu(target->ioc_guid),
+ be64_to_cpu(target->initiator_ext));
+ ret = -EEXIST;
+ goto err;
+ }
+
if (!host->srp_dev->fmr_pool && !target->allow_ext_sg &&
target->cmd_sg_cnt < target->sg_tablesize) {
pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
@@ -2507,6 +2576,8 @@ static void srp_remove_one(struct ib_device *device)
struct srp_target_port *target;
srp_dev = ib_get_client_data(device, &srp_client);
+ if (!srp_dev)
+ return;
list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
device_unregister(&host->dev);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 66fbedda4571..e641088c14dc 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -156,6 +156,7 @@ struct srp_target_port {
char target_name[32];
unsigned int scsi_id;
unsigned int sg_tablesize;
+ int comp_vector;
struct ib_sa_path_rec path;
__be16 orig_dgid[8];
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 3f3f0416fbdd..653ac6bfc57a 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3011,7 +3011,7 @@ static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status)
* Callback function called by the TCM core. Must not block since it can be
* invoked on the context of the IB completion handler.
*/
-static int srpt_queue_response(struct se_cmd *cmd)
+static void srpt_queue_response(struct se_cmd *cmd)
{
struct srpt_rdma_ch *ch;
struct srpt_send_ioctx *ioctx;
@@ -3022,8 +3022,6 @@ static int srpt_queue_response(struct se_cmd *cmd)
int resp_len;
u8 srp_tm_status;
- ret = 0;
-
ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
ch = ioctx->ch;
BUG_ON(!ch);
@@ -3049,7 +3047,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
|| WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
atomic_inc(&ch->req_lim_delta);
srpt_abort_cmd(ioctx);
- goto out;
+ return;
}
dir = ioctx->cmd.data_direction;
@@ -3061,7 +3059,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
if (ret) {
printk(KERN_ERR "xfer_data failed for tag %llu\n",
ioctx->tag);
- goto out;
+ return;
}
}
@@ -3082,9 +3080,17 @@ static int srpt_queue_response(struct se_cmd *cmd)
srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd);
}
+}
-out:
- return ret;
+static int srpt_queue_data_in(struct se_cmd *cmd)
+{
+ srpt_queue_response(cmd);
+ return 0;
+}
+
+static void srpt_queue_tm_rsp(struct se_cmd *cmd)
+{
+ srpt_queue_response(cmd);
}
static int srpt_queue_status(struct se_cmd *cmd)
@@ -3097,7 +3103,8 @@ static int srpt_queue_status(struct se_cmd *cmd)
(SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE))
WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION);
ioctx->queue_status_only = true;
- return srpt_queue_response(cmd);
+ srpt_queue_response(cmd);
+ return 0;
}
static void srpt_refresh_port_work(struct work_struct *work)
@@ -3930,9 +3937,9 @@ static struct target_core_fabric_ops srpt_template = {
.set_default_node_attributes = srpt_set_default_node_attrs,
.get_task_tag = srpt_get_task_tag,
.get_cmd_state = srpt_get_tcm_cmd_state,
- .queue_data_in = srpt_queue_response,
+ .queue_data_in = srpt_queue_data_in,
.queue_status = srpt_queue_status,
- .queue_tm_rsp = srpt_queue_response,
+ .queue_tm_rsp = srpt_queue_tm_rsp,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 01730b2b9954..820d85c4a4a0 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -269,4 +269,17 @@ config SPAPR_TCE_IOMMU
Enables bits of IOMMU API required by VFIO. The iommu_ops
is not implemented as it is not necessary for VFIO.
+config ARM_SMMU
+ bool "ARM Ltd. System MMU (SMMU) Support"
+ depends on ARM64 || (ARM_LPAE && OF)
+ select IOMMU_API
+ select ARM_DMA_USE_IOMMU if ARM
+ help
+ Support for implementations of the ARM System MMU architecture
+ versions 1 and 2. The driver supports both v7l and v8l table
+ formats with 4k and 64k page sizes.
+
+ Say Y here if your SoC includes an IOMMU device implementing
+ the ARM SMMU architecture.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index ef0e5207ad69..bbe7041212dd 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_OF_IOMMU) += of_iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
+obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 21d02b0d907c..6dc659426a51 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -287,14 +287,27 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev)
/*
* If it's a multifunction device that does not support our
- * required ACS flags, add to the same group as function 0.
+ * required ACS flags, add to the same group as lowest numbered
+ * function that also does not suport the required ACS flags.
*/
if (dma_pdev->multifunction &&
- !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
- swap_pci_ref(&dma_pdev,
- pci_get_slot(dma_pdev->bus,
- PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
- 0)));
+ !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+ u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+ for (i = 0; i < 8; i++) {
+ struct pci_dev *tmp;
+
+ tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+ if (!tmp)
+ continue;
+
+ if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+ swap_pci_ref(&dma_pdev, tmp);
+ break;
+ }
+ pci_dev_put(tmp);
+ }
+ }
/*
* Devices on the root bus go through the iommu. If that's not us,
@@ -1484,6 +1497,10 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
/* Large PTE found which maps this address */
unmap_size = PTE_PAGE_SIZE(*pte);
+
+ /* Only unmap from the first pte in the page */
+ if ((unmap_size - 1) & bus_addr)
+ break;
count = PAGE_SIZE_PTE_COUNT(unmap_size);
for (i = 0; i < count; i++)
pte[i] = 0ULL;
@@ -1493,7 +1510,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
unmapped += unmap_size;
}
- BUG_ON(!is_power_of_2(unmapped));
+ BUG_ON(unmapped && !is_power_of_2(unmapped));
return unmapped;
}
@@ -1893,34 +1910,59 @@ static void domain_id_free(int id)
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
}
+#define DEFINE_FREE_PT_FN(LVL, FN) \
+static void free_pt_##LVL (unsigned long __pt) \
+{ \
+ unsigned long p; \
+ u64 *pt; \
+ int i; \
+ \
+ pt = (u64 *)__pt; \
+ \
+ for (i = 0; i < 512; ++i) { \
+ if (!IOMMU_PTE_PRESENT(pt[i])) \
+ continue; \
+ \
+ p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
+ FN(p); \
+ } \
+ free_page((unsigned long)pt); \
+}
+
+DEFINE_FREE_PT_FN(l2, free_page)
+DEFINE_FREE_PT_FN(l3, free_pt_l2)
+DEFINE_FREE_PT_FN(l4, free_pt_l3)
+DEFINE_FREE_PT_FN(l5, free_pt_l4)
+DEFINE_FREE_PT_FN(l6, free_pt_l5)
+
static void free_pagetable(struct protection_domain *domain)
{
- int i, j;
- u64 *p1, *p2, *p3;
-
- p1 = domain->pt_root;
-
- if (!p1)
- return;
-
- for (i = 0; i < 512; ++i) {
- if (!IOMMU_PTE_PRESENT(p1[i]))
- continue;
-
- p2 = IOMMU_PTE_PAGE(p1[i]);
- for (j = 0; j < 512; ++j) {
- if (!IOMMU_PTE_PRESENT(p2[j]))
- continue;
- p3 = IOMMU_PTE_PAGE(p2[j]);
- free_page((unsigned long)p3);
- }
+ unsigned long root = (unsigned long)domain->pt_root;
- free_page((unsigned long)p2);
+ switch (domain->mode) {
+ case PAGE_MODE_NONE:
+ break;
+ case PAGE_MODE_1_LEVEL:
+ free_page(root);
+ break;
+ case PAGE_MODE_2_LEVEL:
+ free_pt_l2(root);
+ break;
+ case PAGE_MODE_3_LEVEL:
+ free_pt_l3(root);
+ break;
+ case PAGE_MODE_4_LEVEL:
+ free_pt_l4(root);
+ break;
+ case PAGE_MODE_5_LEVEL:
+ free_pt_l5(root);
+ break;
+ case PAGE_MODE_6_LEVEL:
+ free_pt_l6(root);
+ break;
+ default:
+ BUG();
}
-
- free_page((unsigned long)p1);
-
- domain->pt_root = NULL;
}
static void free_gcr3_tbl_level1(u64 *tbl)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
new file mode 100644
index 000000000000..ebd0a4cff049
--- /dev/null
+++ b/drivers/iommu/arm-smmu.c
@@ -0,0 +1,1969 @@
+/*
+ * IOMMU API for ARM architected SMMU implementations.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2013 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This driver currently supports:
+ * - SMMUv1 and v2 implementations
+ * - Stream-matching and stream-indexing
+ * - v7/v8 long-descriptor format
+ * - Non-secure access to the SMMU
+ * - 4k and 64k pages, with contiguous pte hints.
+ * - Up to 39-bit addressing
+ * - Context fault reporting
+ */
+
+#define pr_fmt(fmt) "arm-smmu: " fmt
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/pgalloc.h>
+
+/* Maximum number of stream IDs assigned to a single device */
+#define MAX_MASTER_STREAMIDS 8
+
+/* Maximum number of context banks per SMMU */
+#define ARM_SMMU_MAX_CBS 128
+
+/* Maximum number of mapping groups per SMMU */
+#define ARM_SMMU_MAX_SMRS 128
+
+/* Number of VMIDs per SMMU */
+#define ARM_SMMU_NUM_VMIDS 256
+
+/* SMMU global address space */
+#define ARM_SMMU_GR0(smmu) ((smmu)->base)
+#define ARM_SMMU_GR1(smmu) ((smmu)->base + (smmu)->pagesize)
+
+/* Page table bits */
+#define ARM_SMMU_PTE_PAGE (((pteval_t)3) << 0)
+#define ARM_SMMU_PTE_CONT (((pteval_t)1) << 52)
+#define ARM_SMMU_PTE_AF (((pteval_t)1) << 10)
+#define ARM_SMMU_PTE_SH_NS (((pteval_t)0) << 8)
+#define ARM_SMMU_PTE_SH_OS (((pteval_t)2) << 8)
+#define ARM_SMMU_PTE_SH_IS (((pteval_t)3) << 8)
+
+#if PAGE_SIZE == SZ_4K
+#define ARM_SMMU_PTE_CONT_ENTRIES 16
+#elif PAGE_SIZE == SZ_64K
+#define ARM_SMMU_PTE_CONT_ENTRIES 32
+#else
+#define ARM_SMMU_PTE_CONT_ENTRIES 1
+#endif
+
+#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
+#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1))
+#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t))
+
+/* Stage-1 PTE */
+#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2
+
+/* Stage-2 PTE */
+#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6)
+#define ARM_SMMU_PTE_HAP_READ (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_HAP_WRITE (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_MEMATTR_OIWB (((pteval_t)0xf) << 2)
+#define ARM_SMMU_PTE_MEMATTR_NC (((pteval_t)0x5) << 2)
+#define ARM_SMMU_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2)
+
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0 0x0
+#define sCR0_CLIENTPD (1 << 0)
+#define sCR0_GFRE (1 << 1)
+#define sCR0_GFIE (1 << 2)
+#define sCR0_GCFGFRE (1 << 4)
+#define sCR0_GCFGFIE (1 << 5)
+#define sCR0_USFCFG (1 << 10)
+#define sCR0_VMIDPNE (1 << 11)
+#define sCR0_PTM (1 << 12)
+#define sCR0_FB (1 << 13)
+#define sCR0_BSU_SHIFT 14
+#define sCR0_BSU_MASK 0x3
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0 0x20
+#define ARM_SMMU_GR0_ID1 0x24
+#define ARM_SMMU_GR0_ID2 0x28
+#define ARM_SMMU_GR0_ID3 0x2c
+#define ARM_SMMU_GR0_ID4 0x30
+#define ARM_SMMU_GR0_ID5 0x34
+#define ARM_SMMU_GR0_ID6 0x38
+#define ARM_SMMU_GR0_ID7 0x3c
+#define ARM_SMMU_GR0_sGFSR 0x48
+#define ARM_SMMU_GR0_sGFSYNR0 0x50
+#define ARM_SMMU_GR0_sGFSYNR1 0x54
+#define ARM_SMMU_GR0_sGFSYNR2 0x58
+#define ARM_SMMU_GR0_PIDR0 0xfe0
+#define ARM_SMMU_GR0_PIDR1 0xfe4
+#define ARM_SMMU_GR0_PIDR2 0xfe8
+
+#define ID0_S1TS (1 << 30)
+#define ID0_S2TS (1 << 29)
+#define ID0_NTS (1 << 28)
+#define ID0_SMS (1 << 27)
+#define ID0_PTFS_SHIFT 24
+#define ID0_PTFS_MASK 0x2
+#define ID0_PTFS_V8_ONLY 0x2
+#define ID0_CTTW (1 << 14)
+#define ID0_NUMIRPT_SHIFT 16
+#define ID0_NUMIRPT_MASK 0xff
+#define ID0_NUMSMRG_SHIFT 0
+#define ID0_NUMSMRG_MASK 0xff
+
+#define ID1_PAGESIZE (1 << 31)
+#define ID1_NUMPAGENDXB_SHIFT 28
+#define ID1_NUMPAGENDXB_MASK 7
+#define ID1_NUMS2CB_SHIFT 16
+#define ID1_NUMS2CB_MASK 0xff
+#define ID1_NUMCB_SHIFT 0
+#define ID1_NUMCB_MASK 0xff
+
+#define ID2_OAS_SHIFT 4
+#define ID2_OAS_MASK 0xf
+#define ID2_IAS_SHIFT 0
+#define ID2_IAS_MASK 0xf
+#define ID2_UBS_SHIFT 8
+#define ID2_UBS_MASK 0xf
+#define ID2_PTFS_4K (1 << 12)
+#define ID2_PTFS_16K (1 << 13)
+#define ID2_PTFS_64K (1 << 14)
+
+#define PIDR2_ARCH_SHIFT 4
+#define PIDR2_ARCH_MASK 0xf
+
+/* Global TLB invalidation */
+#define ARM_SMMU_GR0_STLBIALL 0x60
+#define ARM_SMMU_GR0_TLBIVMID 0x64
+#define ARM_SMMU_GR0_TLBIALLNSNH 0x68
+#define ARM_SMMU_GR0_TLBIALLH 0x6c
+#define ARM_SMMU_GR0_sTLBGSYNC 0x70
+#define ARM_SMMU_GR0_sTLBGSTATUS 0x74
+#define sTLBGSTATUS_GSACTIVE (1 << 0)
+#define TLB_LOOP_TIMEOUT 1000000 /* 1s! */
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2))
+#define SMR_VALID (1 << 31)
+#define SMR_MASK_SHIFT 16
+#define SMR_MASK_MASK 0x7fff
+#define SMR_ID_SHIFT 0
+#define SMR_ID_MASK 0x7fff
+
+#define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2))
+#define S2CR_CBNDX_SHIFT 0
+#define S2CR_CBNDX_MASK 0xff
+#define S2CR_TYPE_SHIFT 16
+#define S2CR_TYPE_MASK 0x3
+#define S2CR_TYPE_TRANS (0 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_BYPASS (1 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_FAULT (2 << S2CR_TYPE_SHIFT)
+
+/* Context bank attribute registers */
+#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2))
+#define CBAR_VMID_SHIFT 0
+#define CBAR_VMID_MASK 0xff
+#define CBAR_S1_MEMATTR_SHIFT 12
+#define CBAR_S1_MEMATTR_MASK 0xf
+#define CBAR_S1_MEMATTR_WB 0xf
+#define CBAR_TYPE_SHIFT 16
+#define CBAR_TYPE_MASK 0x3
+#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_BYPASS (1 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_FAULT (2 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_TRANS (3 << CBAR_TYPE_SHIFT)
+#define CBAR_IRPTNDX_SHIFT 24
+#define CBAR_IRPTNDX_MASK 0xff
+
+#define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2))
+#define CBA2R_RW64_32BIT (0 << 0)
+#define CBA2R_RW64_64BIT (1 << 0)
+
+/* Translation context bank */
+#define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1))
+#define ARM_SMMU_CB(smmu, n) ((n) * (smmu)->pagesize)
+
+#define ARM_SMMU_CB_SCTLR 0x0
+#define ARM_SMMU_CB_RESUME 0x8
+#define ARM_SMMU_CB_TTBCR2 0x10
+#define ARM_SMMU_CB_TTBR0_LO 0x20
+#define ARM_SMMU_CB_TTBR0_HI 0x24
+#define ARM_SMMU_CB_TTBCR 0x30
+#define ARM_SMMU_CB_S1_MAIR0 0x38
+#define ARM_SMMU_CB_FSR 0x58
+#define ARM_SMMU_CB_FAR_LO 0x60
+#define ARM_SMMU_CB_FAR_HI 0x64
+#define ARM_SMMU_CB_FSYNR0 0x68
+
+#define SCTLR_S1_ASIDPNE (1 << 12)
+#define SCTLR_CFCFG (1 << 7)
+#define SCTLR_CFIE (1 << 6)
+#define SCTLR_CFRE (1 << 5)
+#define SCTLR_E (1 << 4)
+#define SCTLR_AFE (1 << 2)
+#define SCTLR_TRE (1 << 1)
+#define SCTLR_M (1 << 0)
+#define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE)
+
+#define RESUME_RETRY (0 << 0)
+#define RESUME_TERMINATE (1 << 0)
+
+#define TTBCR_EAE (1 << 31)
+
+#define TTBCR_PASIZE_SHIFT 16
+#define TTBCR_PASIZE_MASK 0x7
+
+#define TTBCR_TG0_4K (0 << 14)
+#define TTBCR_TG0_64K (1 << 14)
+
+#define TTBCR_SH0_SHIFT 12
+#define TTBCR_SH0_MASK 0x3
+#define TTBCR_SH_NS 0
+#define TTBCR_SH_OS 2
+#define TTBCR_SH_IS 3
+
+#define TTBCR_ORGN0_SHIFT 10
+#define TTBCR_IRGN0_SHIFT 8
+#define TTBCR_RGN_MASK 0x3
+#define TTBCR_RGN_NC 0
+#define TTBCR_RGN_WBWA 1
+#define TTBCR_RGN_WT 2
+#define TTBCR_RGN_WB 3
+
+#define TTBCR_SL0_SHIFT 6
+#define TTBCR_SL0_MASK 0x3
+#define TTBCR_SL0_LVL_2 0
+#define TTBCR_SL0_LVL_1 1
+
+#define TTBCR_T1SZ_SHIFT 16
+#define TTBCR_T0SZ_SHIFT 0
+#define TTBCR_SZ_MASK 0xf
+
+#define TTBCR2_SEP_SHIFT 15
+#define TTBCR2_SEP_MASK 0x7
+
+#define TTBCR2_PASIZE_SHIFT 0
+#define TTBCR2_PASIZE_MASK 0x7
+
+/* Common definitions for PASize and SEP fields */
+#define TTBCR2_ADDR_32 0
+#define TTBCR2_ADDR_36 1
+#define TTBCR2_ADDR_40 2
+#define TTBCR2_ADDR_42 3
+#define TTBCR2_ADDR_44 4
+#define TTBCR2_ADDR_48 5
+
+#define MAIR_ATTR_SHIFT(n) ((n) << 3)
+#define MAIR_ATTR_MASK 0xff
+#define MAIR_ATTR_DEVICE 0x04
+#define MAIR_ATTR_NC 0x44
+#define MAIR_ATTR_WBRWA 0xff
+#define MAIR_ATTR_IDX_NC 0
+#define MAIR_ATTR_IDX_CACHE 1
+#define MAIR_ATTR_IDX_DEV 2
+
+#define FSR_MULTI (1 << 31)
+#define FSR_SS (1 << 30)
+#define FSR_UUT (1 << 8)
+#define FSR_ASF (1 << 7)
+#define FSR_TLBLKF (1 << 6)
+#define FSR_TLBMCF (1 << 5)
+#define FSR_EF (1 << 4)
+#define FSR_PF (1 << 3)
+#define FSR_AFF (1 << 2)
+#define FSR_TF (1 << 1)
+
+#define FSR_IGN (FSR_AFF | FSR_ASF | FSR_TLBMCF | \
+ FSR_TLBLKF)
+#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \
+ FSR_EF | FSR_PF | FSR_TF)
+
+#define FSYNR0_WNR (1 << 4)
+
+struct arm_smmu_smr {
+ u8 idx;
+ u16 mask;
+ u16 id;
+};
+
+struct arm_smmu_master {
+ struct device_node *of_node;
+
+ /*
+ * The following is specific to the master's position in the
+ * SMMU chain.
+ */
+ struct rb_node node;
+ int num_streamids;
+ u16 streamids[MAX_MASTER_STREAMIDS];
+
+ /*
+ * We only need to allocate these on the root SMMU, as we
+ * configure unmatched streams to bypass translation.
+ */
+ struct arm_smmu_smr *smrs;
+};
+
+struct arm_smmu_device {
+ struct device *dev;
+ struct device_node *parent_of_node;
+
+ void __iomem *base;
+ unsigned long size;
+ unsigned long pagesize;
+
+#define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0)
+#define ARM_SMMU_FEAT_STREAM_MATCH (1 << 1)
+#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2)
+#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
+#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
+ u32 features;
+ int version;
+
+ u32 num_context_banks;
+ u32 num_s2_context_banks;
+ DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+ atomic_t irptndx;
+
+ u32 num_mapping_groups;
+ DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
+
+ unsigned long input_size;
+ unsigned long s1_output_size;
+ unsigned long s2_output_size;
+
+ u32 num_global_irqs;
+ u32 num_context_irqs;
+ unsigned int *irqs;
+
+ DECLARE_BITMAP(vmid_map, ARM_SMMU_NUM_VMIDS);
+
+ struct list_head list;
+ struct rb_root masters;
+};
+
+struct arm_smmu_cfg {
+ struct arm_smmu_device *smmu;
+ u8 vmid;
+ u8 cbndx;
+ u8 irptndx;
+ u32 cbar;
+ pgd_t *pgd;
+};
+
+struct arm_smmu_domain {
+ /*
+ * A domain can span across multiple, chained SMMUs and requires
+ * all devices within the domain to follow the same translation
+ * path.
+ */
+ struct arm_smmu_device *leaf_smmu;
+ struct arm_smmu_cfg root_cfg;
+ phys_addr_t output_mask;
+
+ spinlock_t lock;
+};
+
+static DEFINE_SPINLOCK(arm_smmu_devices_lock);
+static LIST_HEAD(arm_smmu_devices);
+
+static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
+ struct device_node *dev_node)
+{
+ struct rb_node *node = smmu->masters.rb_node;
+
+ while (node) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+
+ if (dev_node < master->of_node)
+ node = node->rb_left;
+ else if (dev_node > master->of_node)
+ node = node->rb_right;
+ else
+ return master;
+ }
+
+ return NULL;
+}
+
+static int insert_smmu_master(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ struct rb_node **new, *parent;
+
+ new = &smmu->masters.rb_node;
+ parent = NULL;
+ while (*new) {
+ struct arm_smmu_master *this;
+ this = container_of(*new, struct arm_smmu_master, node);
+
+ parent = *new;
+ if (master->of_node < this->of_node)
+ new = &((*new)->rb_left);
+ else if (master->of_node > this->of_node)
+ new = &((*new)->rb_right);
+ else
+ return -EEXIST;
+ }
+
+ rb_link_node(&master->node, parent, new);
+ rb_insert_color(&master->node, &smmu->masters);
+ return 0;
+}
+
+static int register_smmu_master(struct arm_smmu_device *smmu,
+ struct device *dev,
+ struct of_phandle_args *masterspec)
+{
+ int i;
+ struct arm_smmu_master *master;
+
+ master = find_smmu_master(smmu, masterspec->np);
+ if (master) {
+ dev_err(dev,
+ "rejecting multiple registrations for master device %s\n",
+ masterspec->np->name);
+ return -EBUSY;
+ }
+
+ if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
+ dev_err(dev,
+ "reached maximum number (%d) of stream IDs for master device %s\n",
+ MAX_MASTER_STREAMIDS, masterspec->np->name);
+ return -ENOSPC;
+ }
+
+ master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ master->of_node = masterspec->np;
+ master->num_streamids = masterspec->args_count;
+
+ for (i = 0; i < master->num_streamids; ++i)
+ master->streamids[i] = masterspec->args[i];
+
+ return insert_smmu_master(smmu, master);
+}
+
+static struct arm_smmu_device *find_parent_smmu(struct arm_smmu_device *smmu)
+{
+ struct arm_smmu_device *parent;
+
+ if (!smmu->parent_of_node)
+ return NULL;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(parent, &arm_smmu_devices, list)
+ if (parent->dev->of_node == smmu->parent_of_node)
+ goto out_unlock;
+
+ parent = NULL;
+ dev_warn(smmu->dev,
+ "Failed to find SMMU parent despite parent in DT\n");
+out_unlock:
+ spin_unlock(&arm_smmu_devices_lock);
+ return parent;
+}
+
+static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
+{
+ int idx;
+
+ do {
+ idx = find_next_zero_bit(map, end, start);
+ if (idx == end)
+ return -ENOSPC;
+ } while (test_and_set_bit(idx, map));
+
+ return idx;
+}
+
+static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
+{
+ clear_bit(idx, map);
+}
+
+/* Wait for any pending TLB invalidations to complete */
+static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
+{
+ int count = 0;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_sTLBGSYNC);
+ while (readl_relaxed(gr0_base + ARM_SMMU_GR0_sTLBGSTATUS)
+ & sTLBGSTATUS_GSACTIVE) {
+ cpu_relax();
+ if (++count == TLB_LOOP_TIMEOUT) {
+ dev_err_ratelimited(smmu->dev,
+ "TLB sync timed out -- SMMU may be deadlocked\n");
+ return;
+ }
+ udelay(1);
+ }
+}
+
+static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
+{
+ int flags, ret;
+ u32 fsr, far, fsynr, resume;
+ unsigned long iova;
+ struct iommu_domain *domain = dev;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *cb_base;
+
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+ fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+
+ if (!(fsr & FSR_FAULT))
+ return IRQ_NONE;
+
+ if (fsr & FSR_IGN)
+ dev_err_ratelimited(smmu->dev,
+ "Unexpected context fault (fsr 0x%u)\n",
+ fsr);
+
+ fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
+ flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
+
+ far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_LO);
+ iova = far;
+#ifdef CONFIG_64BIT
+ far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_HI);
+ iova |= ((unsigned long)far << 32);
+#endif
+
+ if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
+ ret = IRQ_HANDLED;
+ resume = RESUME_RETRY;
+ } else {
+ ret = IRQ_NONE;
+ resume = RESUME_TERMINATE;
+ }
+
+ /* Clear the faulting FSR */
+ writel(fsr, cb_base + ARM_SMMU_CB_FSR);
+
+ /* Retry or terminate any stalled transactions */
+ if (fsr & FSR_SS)
+ writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
+
+ return ret;
+}
+
+static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
+{
+ u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
+ struct arm_smmu_device *smmu = dev;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
+ gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
+ gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
+ gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
+
+ dev_err_ratelimited(smmu->dev,
+ "Unexpected global fault, this could be serious\n");
+ dev_err_ratelimited(smmu->dev,
+ "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
+ gfsr, gfsynr0, gfsynr1, gfsynr2);
+
+ writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
+ return IRQ_NONE;
+}
+
+static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
+{
+ u32 reg;
+ bool stage1;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *cb_base, *gr0_base, *gr1_base;
+
+ gr0_base = ARM_SMMU_GR0(smmu);
+ gr1_base = ARM_SMMU_GR1(smmu);
+ stage1 = root_cfg->cbar != CBAR_TYPE_S2_TRANS;
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+
+ /* CBAR */
+ reg = root_cfg->cbar |
+ (root_cfg->vmid << CBAR_VMID_SHIFT);
+ if (smmu->version == 1)
+ reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
+
+ /* Use the weakest memory type, so it is overridden by the pte */
+ if (stage1)
+ reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+ writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
+
+ if (smmu->version > 1) {
+ /* CBA2R */
+#ifdef CONFIG_64BIT
+ reg = CBA2R_RW64_64BIT;
+#else
+ reg = CBA2R_RW64_32BIT;
+#endif
+ writel_relaxed(reg,
+ gr1_base + ARM_SMMU_GR1_CBA2R(root_cfg->cbndx));
+
+ /* TTBCR2 */
+ switch (smmu->input_size) {
+ case 32:
+ reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
+ break;
+ case 36:
+ reg = (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
+ break;
+ case 39:
+ reg = (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
+ break;
+ case 42:
+ reg = (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
+ break;
+ case 44:
+ reg = (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
+ break;
+ case 48:
+ reg = (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
+ break;
+ }
+
+ switch (smmu->s1_output_size) {
+ case 32:
+ reg |= (TTBCR2_ADDR_32 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 36:
+ reg |= (TTBCR2_ADDR_36 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 39:
+ reg |= (TTBCR2_ADDR_40 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 42:
+ reg |= (TTBCR2_ADDR_42 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 44:
+ reg |= (TTBCR2_ADDR_44 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 48:
+ reg |= (TTBCR2_ADDR_48 << TTBCR2_PASIZE_SHIFT);
+ break;
+ }
+
+ if (stage1)
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
+ }
+
+ /* TTBR0 */
+ reg = __pa(root_cfg->pgd);
+#ifndef __BIG_ENDIAN
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+ reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+#else
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+ reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+#endif
+
+ /*
+ * TTBCR
+ * We use long descriptor, with inner-shareable WBWA tables in TTBR0.
+ */
+ if (smmu->version > 1) {
+ if (PAGE_SIZE == SZ_4K)
+ reg = TTBCR_TG0_4K;
+ else
+ reg = TTBCR_TG0_64K;
+
+ if (!stage1) {
+ switch (smmu->s2_output_size) {
+ case 32:
+ reg |= (TTBCR2_ADDR_32 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 36:
+ reg |= (TTBCR2_ADDR_36 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 40:
+ reg |= (TTBCR2_ADDR_40 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 42:
+ reg |= (TTBCR2_ADDR_42 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 44:
+ reg |= (TTBCR2_ADDR_44 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 48:
+ reg |= (TTBCR2_ADDR_48 << TTBCR_PASIZE_SHIFT);
+ break;
+ }
+ } else {
+ reg |= (64 - smmu->s1_output_size) << TTBCR_T0SZ_SHIFT;
+ }
+ } else {
+ reg = 0;
+ }
+
+ reg |= TTBCR_EAE |
+ (TTBCR_SH_IS << TTBCR_SH0_SHIFT) |
+ (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) |
+ (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT) |
+ (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT);
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
+
+ /* MAIR0 (stage-1 only) */
+ if (stage1) {
+ reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) |
+ (MAIR_ATTR_WBRWA << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_CACHE)) |
+ (MAIR_ATTR_DEVICE << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_DEV));
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
+ }
+
+ /* Nuke the TLB */
+ writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+ arm_smmu_tlb_sync(smmu);
+
+ /* SCTLR */
+ reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
+ if (stage1)
+ reg |= SCTLR_S1_ASIDPNE;
+#ifdef __BIG_ENDIAN
+ reg |= SCTLR_E;
+#endif
+ writel(reg, cb_base + ARM_SMMU_CB_SCTLR);
+}
+
+static int arm_smmu_init_domain_context(struct iommu_domain *domain,
+ struct device *dev)
+{
+ int irq, ret, start;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu, *parent;
+
+ /*
+ * Walk the SMMU chain to find the root device for this chain.
+ * We assume that no masters have translations which terminate
+ * early, and therefore check that the root SMMU does indeed have
+ * a StreamID for the master in question.
+ */
+ parent = dev->archdata.iommu;
+ smmu_domain->output_mask = -1;
+ do {
+ smmu = parent;
+ smmu_domain->output_mask &= (1ULL << smmu->s2_output_size) - 1;
+ } while ((parent = find_parent_smmu(smmu)));
+
+ if (!find_smmu_master(smmu, dev->of_node)) {
+ dev_err(dev, "unable to find root SMMU for device\n");
+ return -ENODEV;
+ }
+
+ ret = __arm_smmu_alloc_bitmap(smmu->vmid_map, 0, ARM_SMMU_NUM_VMIDS);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+
+ root_cfg->vmid = ret;
+ if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
+ /*
+ * We will likely want to change this if/when KVM gets
+ * involved.
+ */
+ root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+ start = smmu->num_s2_context_banks;
+ } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S2) {
+ root_cfg->cbar = CBAR_TYPE_S2_TRANS;
+ start = 0;
+ } else {
+ root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+ start = smmu->num_s2_context_banks;
+ }
+
+ ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
+ smmu->num_context_banks);
+ if (IS_ERR_VALUE(ret))
+ goto out_free_vmid;
+
+ root_cfg->cbndx = ret;
+
+ if (smmu->version == 1) {
+ root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
+ root_cfg->irptndx %= smmu->num_context_irqs;
+ } else {
+ root_cfg->irptndx = root_cfg->cbndx;
+ }
+
+ irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+ ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
+ "arm-smmu-context-fault", domain);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
+ root_cfg->irptndx, irq);
+ root_cfg->irptndx = -1;
+ goto out_free_context;
+ }
+
+ root_cfg->smmu = smmu;
+ arm_smmu_init_context_bank(smmu_domain);
+ return ret;
+
+out_free_context:
+ __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+out_free_vmid:
+ __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+ return ret;
+}
+
+static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ int irq;
+
+ if (!smmu)
+ return;
+
+ if (root_cfg->irptndx != -1) {
+ irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+ free_irq(irq, domain);
+ }
+
+ __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+ __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+}
+
+static int arm_smmu_domain_init(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain;
+ pgd_t *pgd;
+
+ /*
+ * Allocate the domain and initialise some of its data structures.
+ * We can't really do anything meaningful until we've added a
+ * master.
+ */
+ smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
+ if (!smmu_domain)
+ return -ENOMEM;
+
+ pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+ if (!pgd)
+ goto out_free_domain;
+ smmu_domain->root_cfg.pgd = pgd;
+
+ spin_lock_init(&smmu_domain->lock);
+ domain->priv = smmu_domain;
+ return 0;
+
+out_free_domain:
+ kfree(smmu_domain);
+ return -ENOMEM;
+}
+
+static void arm_smmu_free_ptes(pmd_t *pmd)
+{
+ pgtable_t table = pmd_pgtable(*pmd);
+ pgtable_page_dtor(table);
+ __free_page(table);
+}
+
+static void arm_smmu_free_pmds(pud_t *pud)
+{
+ int i;
+ pmd_t *pmd, *pmd_base = pmd_offset(pud, 0);
+
+ pmd = pmd_base;
+ for (i = 0; i < PTRS_PER_PMD; ++i) {
+ if (pmd_none(*pmd))
+ continue;
+
+ arm_smmu_free_ptes(pmd);
+ pmd++;
+ }
+
+ pmd_free(NULL, pmd_base);
+}
+
+static void arm_smmu_free_puds(pgd_t *pgd)
+{
+ int i;
+ pud_t *pud, *pud_base = pud_offset(pgd, 0);
+
+ pud = pud_base;
+ for (i = 0; i < PTRS_PER_PUD; ++i) {
+ if (pud_none(*pud))
+ continue;
+
+ arm_smmu_free_pmds(pud);
+ pud++;
+ }
+
+ pud_free(NULL, pud_base);
+}
+
+static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
+{
+ int i;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ pgd_t *pgd, *pgd_base = root_cfg->pgd;
+
+ /*
+ * Recursively free the page tables for this domain. We don't
+ * care about speculative TLB filling, because the TLB will be
+ * nuked next time this context bank is re-allocated and no devices
+ * currently map to these tables.
+ */
+ pgd = pgd_base;
+ for (i = 0; i < PTRS_PER_PGD; ++i) {
+ if (pgd_none(*pgd))
+ continue;
+ arm_smmu_free_puds(pgd);
+ pgd++;
+ }
+
+ kfree(pgd_base);
+}
+
+static void arm_smmu_domain_destroy(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ arm_smmu_destroy_domain_context(domain);
+ arm_smmu_free_pgtables(smmu_domain);
+ kfree(smmu_domain);
+}
+
+static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ struct arm_smmu_smr *smrs;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH))
+ return 0;
+
+ if (master->smrs)
+ return -EEXIST;
+
+ smrs = kmalloc(sizeof(*smrs) * master->num_streamids, GFP_KERNEL);
+ if (!smrs) {
+ dev_err(smmu->dev, "failed to allocate %d SMRs for master %s\n",
+ master->num_streamids, master->of_node->name);
+ return -ENOMEM;
+ }
+
+ /* Allocate the SMRs on the root SMMU */
+ for (i = 0; i < master->num_streamids; ++i) {
+ int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
+ smmu->num_mapping_groups);
+ if (IS_ERR_VALUE(idx)) {
+ dev_err(smmu->dev, "failed to allocate free SMR\n");
+ goto err_free_smrs;
+ }
+
+ smrs[i] = (struct arm_smmu_smr) {
+ .idx = idx,
+ .mask = 0, /* We don't currently share SMRs */
+ .id = master->streamids[i],
+ };
+ }
+
+ /* It worked! Now, poke the actual hardware */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT |
+ smrs[i].mask << SMR_MASK_SHIFT;
+ writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx));
+ }
+
+ master->smrs = smrs;
+ return 0;
+
+err_free_smrs:
+ while (--i >= 0)
+ __arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx);
+ kfree(smrs);
+ return -ENOSPC;
+}
+
+static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ struct arm_smmu_smr *smrs = master->smrs;
+
+ /* Invalidate the SMRs before freeing back to the allocator */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u8 idx = smrs[i].idx;
+ writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(idx));
+ __arm_smmu_free_bitmap(smmu->smr_map, idx);
+ }
+
+ master->smrs = NULL;
+ kfree(smrs);
+}
+
+static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ for (i = 0; i < master->num_streamids; ++i) {
+ u16 sid = master->streamids[i];
+ writel_relaxed(S2CR_TYPE_BYPASS,
+ gr0_base + ARM_SMMU_GR0_S2CR(sid));
+ }
+}
+
+static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master)
+{
+ int i, ret;
+ struct arm_smmu_device *parent, *smmu = smmu_domain->root_cfg.smmu;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ ret = arm_smmu_master_configure_smrs(smmu, master);
+ if (ret)
+ return ret;
+
+ /* Bypass the leaves */
+ smmu = smmu_domain->leaf_smmu;
+ while ((parent = find_parent_smmu(smmu))) {
+ /*
+ * We won't have a StreamID match for anything but the root
+ * smmu, so we only need to worry about StreamID indexing,
+ * where we must install bypass entries in the S2CRs.
+ */
+ if (smmu->features & ARM_SMMU_FEAT_STREAM_MATCH)
+ continue;
+
+ arm_smmu_bypass_stream_mapping(smmu, master);
+ smmu = parent;
+ }
+
+ /* Now we're at the root, time to point at our context bank */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u32 idx, s2cr;
+ idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
+ s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
+ (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
+ writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
+ }
+
+ return 0;
+}
+
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master)
+{
+ struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
+
+ /*
+ * We *must* clear the S2CR first, because freeing the SMR means
+ * that it can be re-allocated immediately.
+ */
+ arm_smmu_bypass_stream_mapping(smmu, master);
+ arm_smmu_master_free_smrs(smmu, master);
+}
+
+static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ int ret = -EINVAL;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_device *device_smmu = dev->archdata.iommu;
+ struct arm_smmu_master *master;
+
+ if (!device_smmu) {
+ dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
+ return -ENXIO;
+ }
+
+ /*
+ * Sanity check the domain. We don't currently support domains
+ * that cross between different SMMU chains.
+ */
+ spin_lock(&smmu_domain->lock);
+ if (!smmu_domain->leaf_smmu) {
+ /* Now that we have a master, we can finalise the domain */
+ ret = arm_smmu_init_domain_context(domain, dev);
+ if (IS_ERR_VALUE(ret))
+ goto err_unlock;
+
+ smmu_domain->leaf_smmu = device_smmu;
+ } else if (smmu_domain->leaf_smmu != device_smmu) {
+ dev_err(dev,
+ "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
+ dev_name(smmu_domain->leaf_smmu->dev),
+ dev_name(device_smmu->dev));
+ goto err_unlock;
+ }
+ spin_unlock(&smmu_domain->lock);
+
+ /* Looks ok, so add the device to the domain */
+ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+ if (!master)
+ return -ENODEV;
+
+ return arm_smmu_domain_add_master(smmu_domain, master);
+
+err_unlock:
+ spin_unlock(&smmu_domain->lock);
+ return ret;
+}
+
+static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_master *master;
+
+ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+ if (master)
+ arm_smmu_domain_remove_master(smmu_domain, master);
+}
+
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+ size_t size)
+{
+ unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+ /*
+ * If the SMMU can't walk tables in the CPU caches, treat them
+ * like non-coherent DMA since we need to flush the new entries
+ * all the way out to memory. There's no possibility of recursion
+ * here as the SMMU table walker will not be wired through another
+ * SMMU.
+ */
+ if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
+ dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+ DMA_TO_DEVICE);
+}
+
+static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
+ unsigned long end)
+{
+ return !(addr & ~ARM_SMMU_PTE_CONT_MASK) &&
+ (addr + ARM_SMMU_PTE_CONT_SIZE <= end);
+}
+
+static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ unsigned long pfn, int flags, int stage)
+{
+ pte_t *pte, *start;
+ pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
+
+ if (pmd_none(*pmd)) {
+ /* Allocate a new set of tables */
+ pgtable_t table = alloc_page(PGALLOC_GFP);
+ if (!table)
+ return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, page_address(table),
+ ARM_SMMU_PTE_HWTABLE_SIZE);
+ pgtable_page_ctor(table);
+ pmd_populate(NULL, pmd, table);
+ arm_smmu_flush_pgtable(smmu, pmd, sizeof(*pmd));
+ }
+
+ if (stage == 1) {
+ pteval |= ARM_SMMU_PTE_AP_UNPRIV;
+ if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
+ pteval |= ARM_SMMU_PTE_AP_RDONLY;
+
+ if (flags & IOMMU_CACHE)
+ pteval |= (MAIR_ATTR_IDX_CACHE <<
+ ARM_SMMU_PTE_ATTRINDX_SHIFT);
+ } else {
+ pteval |= ARM_SMMU_PTE_HAP_FAULT;
+ if (flags & IOMMU_READ)
+ pteval |= ARM_SMMU_PTE_HAP_READ;
+ if (flags & IOMMU_WRITE)
+ pteval |= ARM_SMMU_PTE_HAP_WRITE;
+ if (flags & IOMMU_CACHE)
+ pteval |= ARM_SMMU_PTE_MEMATTR_OIWB;
+ else
+ pteval |= ARM_SMMU_PTE_MEMATTR_NC;
+ }
+
+ /* If no access, create a faulting entry to avoid TLB fills */
+ if (!(flags & (IOMMU_READ | IOMMU_WRITE)))
+ pteval &= ~ARM_SMMU_PTE_PAGE;
+
+ pteval |= ARM_SMMU_PTE_SH_IS;
+ start = pmd_page_vaddr(*pmd) + pte_index(addr);
+ pte = start;
+
+ /*
+ * Install the page table entries. This is fairly complicated
+ * since we attempt to make use of the contiguous hint in the
+ * ptes where possible. The contiguous hint indicates a series
+ * of ARM_SMMU_PTE_CONT_ENTRIES ptes mapping a physically
+ * contiguous region with the following constraints:
+ *
+ * - The region start is aligned to ARM_SMMU_PTE_CONT_SIZE
+ * - Each pte in the region has the contiguous hint bit set
+ *
+ * This complicates unmapping (also handled by this code, when
+ * neither IOMMU_READ or IOMMU_WRITE are set) because it is
+ * possible, yet highly unlikely, that a client may unmap only
+ * part of a contiguous range. This requires clearing of the
+ * contiguous hint bits in the range before installing the new
+ * faulting entries.
+ *
+ * Note that re-mapping an address range without first unmapping
+ * it is not supported, so TLB invalidation is not required here
+ * and is instead performed at unmap and domain-init time.
+ */
+ do {
+ int i = 1;
+ pteval &= ~ARM_SMMU_PTE_CONT;
+
+ if (arm_smmu_pte_is_contiguous_range(addr, end)) {
+ i = ARM_SMMU_PTE_CONT_ENTRIES;
+ pteval |= ARM_SMMU_PTE_CONT;
+ } else if (pte_val(*pte) &
+ (ARM_SMMU_PTE_CONT | ARM_SMMU_PTE_PAGE)) {
+ int j;
+ pte_t *cont_start;
+ unsigned long idx = pte_index(addr);
+
+ idx &= ~(ARM_SMMU_PTE_CONT_ENTRIES - 1);
+ cont_start = pmd_page_vaddr(*pmd) + idx;
+ for (j = 0; j < ARM_SMMU_PTE_CONT_ENTRIES; ++j)
+ pte_val(*(cont_start + j)) &= ~ARM_SMMU_PTE_CONT;
+
+ arm_smmu_flush_pgtable(smmu, cont_start,
+ sizeof(*pte) *
+ ARM_SMMU_PTE_CONT_ENTRIES);
+ }
+
+ do {
+ *pte = pfn_pte(pfn, __pgprot(pteval));
+ } while (pte++, pfn++, addr += PAGE_SIZE, --i);
+ } while (addr != end);
+
+ arm_smmu_flush_pgtable(smmu, start, sizeof(*pte) * (pte - start));
+ return 0;
+}
+
+static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
+ unsigned long addr, unsigned long end,
+ phys_addr_t phys, int flags, int stage)
+{
+ int ret;
+ pmd_t *pmd;
+ unsigned long next, pfn = __phys_to_pfn(phys);
+
+#ifndef __PAGETABLE_PMD_FOLDED
+ if (pud_none(*pud)) {
+ pmd = pmd_alloc_one(NULL, addr);
+ if (!pmd)
+ return -ENOMEM;
+ } else
+#endif
+ pmd = pmd_offset(pud, addr);
+
+ do {
+ next = pmd_addr_end(addr, end);
+ ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
+ flags, stage);
+ pud_populate(NULL, pud, pmd);
+ arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+ phys += next - addr;
+ } while (pmd++, addr = next, addr < end);
+
+ return ret;
+}
+
+static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
+ unsigned long addr, unsigned long end,
+ phys_addr_t phys, int flags, int stage)
+{
+ int ret = 0;
+ pud_t *pud;
+ unsigned long next;
+
+#ifndef __PAGETABLE_PUD_FOLDED
+ if (pgd_none(*pgd)) {
+ pud = pud_alloc_one(NULL, addr);
+ if (!pud)
+ return -ENOMEM;
+ } else
+#endif
+ pud = pud_offset(pgd, addr);
+
+ do {
+ next = pud_addr_end(addr, end);
+ ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
+ flags, stage);
+ pgd_populate(NULL, pud, pgd);
+ arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+ phys += next - addr;
+ } while (pud++, addr = next, addr < end);
+
+ return ret;
+}
+
+static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
+ unsigned long iova, phys_addr_t paddr,
+ size_t size, int flags)
+{
+ int ret, stage;
+ unsigned long end;
+ phys_addr_t input_mask, output_mask;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ pgd_t *pgd = root_cfg->pgd;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+
+ if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
+ stage = 2;
+ output_mask = (1ULL << smmu->s2_output_size) - 1;
+ } else {
+ stage = 1;
+ output_mask = (1ULL << smmu->s1_output_size) - 1;
+ }
+
+ if (!pgd)
+ return -EINVAL;
+
+ if (size & ~PAGE_MASK)
+ return -EINVAL;
+
+ input_mask = (1ULL << smmu->input_size) - 1;
+ if ((phys_addr_t)iova & ~input_mask)
+ return -ERANGE;
+
+ if (paddr & ~output_mask)
+ return -ERANGE;
+
+ spin_lock(&smmu_domain->lock);
+ pgd += pgd_index(iova);
+ end = iova + size;
+ do {
+ unsigned long next = pgd_addr_end(iova, end);
+
+ ret = arm_smmu_alloc_init_pud(smmu, pgd, iova, next, paddr,
+ flags, stage);
+ if (ret)
+ goto out_unlock;
+
+ paddr += next - iova;
+ iova = next;
+ } while (pgd++, iova != end);
+
+out_unlock:
+ spin_unlock(&smmu_domain->lock);
+
+ /* Ensure new page tables are visible to the hardware walker */
+ if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ dsb();
+
+ return ret;
+}
+
+static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int flags)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_device *smmu = smmu_domain->leaf_smmu;
+
+ if (!smmu_domain || !smmu)
+ return -ENODEV;
+
+ /* Check for silent address truncation up the SMMU chain. */
+ if ((phys_addr_t)iova & ~smmu_domain->output_mask)
+ return -ERANGE;
+
+ return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, flags);
+}
+
+static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
+{
+ int ret;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
+ writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+ arm_smmu_tlb_sync(smmu);
+ return ret ? ret : size;
+}
+
+static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+
+ spin_lock(&smmu_domain->lock);
+ pgd = root_cfg->pgd;
+ if (!pgd)
+ goto err_unlock;
+
+ pgd += pgd_index(iova);
+ if (pgd_none_or_clear_bad(pgd))
+ goto err_unlock;
+
+ pud = pud_offset(pgd, iova);
+ if (pud_none_or_clear_bad(pud))
+ goto err_unlock;
+
+ pmd = pmd_offset(pud, iova);
+ if (pmd_none_or_clear_bad(pmd))
+ goto err_unlock;
+
+ pte = pmd_page_vaddr(*pmd) + pte_index(iova);
+ if (pte_none(pte))
+ goto err_unlock;
+
+ spin_unlock(&smmu_domain->lock);
+ return __pfn_to_phys(pte_pfn(*pte)) | (iova & ~PAGE_MASK);
+
+err_unlock:
+ spin_unlock(&smmu_domain->lock);
+ dev_warn(smmu->dev,
+ "invalid (corrupt?) page tables detected for iova 0x%llx\n",
+ (unsigned long long)iova);
+ return -EINVAL;
+}
+
+static int arm_smmu_domain_has_cap(struct iommu_domain *domain,
+ unsigned long cap)
+{
+ unsigned long caps = 0;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+
+ if (smmu_domain->root_cfg.smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ caps |= IOMMU_CAP_CACHE_COHERENCY;
+
+ return !!(cap & caps);
+}
+
+static int arm_smmu_add_device(struct device *dev)
+{
+ struct arm_smmu_device *child, *parent, *smmu;
+ struct arm_smmu_master *master = NULL;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(parent, &arm_smmu_devices, list) {
+ smmu = parent;
+
+ /* Try to find a child of the current SMMU. */
+ list_for_each_entry(child, &arm_smmu_devices, list) {
+ if (child->parent_of_node == parent->dev->of_node) {
+ /* Does the child sit above our master? */
+ master = find_smmu_master(child, dev->of_node);
+ if (master) {
+ smmu = NULL;
+ break;
+ }
+ }
+ }
+
+ /* We found some children, so keep searching. */
+ if (!smmu) {
+ master = NULL;
+ continue;
+ }
+
+ master = find_smmu_master(smmu, dev->of_node);
+ if (master)
+ break;
+ }
+ spin_unlock(&arm_smmu_devices_lock);
+
+ if (!master)
+ return -ENODEV;
+
+ dev->archdata.iommu = smmu;
+ return 0;
+}
+
+static void arm_smmu_remove_device(struct device *dev)
+{
+ dev->archdata.iommu = NULL;
+}
+
+static struct iommu_ops arm_smmu_ops = {
+ .domain_init = arm_smmu_domain_init,
+ .domain_destroy = arm_smmu_domain_destroy,
+ .attach_dev = arm_smmu_attach_dev,
+ .detach_dev = arm_smmu_detach_dev,
+ .map = arm_smmu_map,
+ .unmap = arm_smmu_unmap,
+ .iova_to_phys = arm_smmu_iova_to_phys,
+ .domain_has_cap = arm_smmu_domain_has_cap,
+ .add_device = arm_smmu_add_device,
+ .remove_device = arm_smmu_remove_device,
+ .pgsize_bitmap = (SECTION_SIZE |
+ ARM_SMMU_PTE_CONT_SIZE |
+ PAGE_SIZE),
+};
+
+static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
+{
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ int i = 0;
+ u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
+
+ /* Mark all SMRn as invalid and all S2CRn as bypass */
+ for (i = 0; i < smmu->num_mapping_groups; ++i) {
+ writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(i));
+ writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
+ }
+
+ /* Invalidate the TLB, just in case */
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
+
+ /* Enable fault reporting */
+ scr0 |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE);
+
+ /* Disable TLB broadcasting. */
+ scr0 |= (sCR0_VMIDPNE | sCR0_PTM);
+
+ /* Enable client access, but bypass when no mapping is found */
+ scr0 &= ~(sCR0_CLIENTPD | sCR0_USFCFG);
+
+ /* Disable forced broadcasting */
+ scr0 &= ~sCR0_FB;
+
+ /* Don't upgrade barriers */
+ scr0 &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
+
+ /* Push the button */
+ arm_smmu_tlb_sync(smmu);
+ writel(scr0, gr0_base + ARM_SMMU_GR0_sCR0);
+}
+
+static int arm_smmu_id_size_to_bits(int size)
+{
+ switch (size) {
+ case 0:
+ return 32;
+ case 1:
+ return 36;
+ case 2:
+ return 40;
+ case 3:
+ return 42;
+ case 4:
+ return 44;
+ case 5:
+ default:
+ return 48;
+ }
+}
+
+static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
+{
+ unsigned long size;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ u32 id;
+
+ dev_notice(smmu->dev, "probing hardware configuration...\n");
+
+ /* Primecell ID */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_PIDR2);
+ smmu->version = ((id >> PIDR2_ARCH_SHIFT) & PIDR2_ARCH_MASK) + 1;
+ dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
+
+ /* ID0 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
+#ifndef CONFIG_64BIT
+ if (((id >> ID0_PTFS_SHIFT) & ID0_PTFS_MASK) == ID0_PTFS_V8_ONLY) {
+ dev_err(smmu->dev, "\tno v7 descriptor support!\n");
+ return -ENODEV;
+ }
+#endif
+ if (id & ID0_S1TS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
+ dev_notice(smmu->dev, "\tstage 1 translation\n");
+ }
+
+ if (id & ID0_S2TS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
+ dev_notice(smmu->dev, "\tstage 2 translation\n");
+ }
+
+ if (id & ID0_NTS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_NESTED;
+ dev_notice(smmu->dev, "\tnested translation\n");
+ }
+
+ if (!(smmu->features &
+ (ARM_SMMU_FEAT_TRANS_S1 | ARM_SMMU_FEAT_TRANS_S2 |
+ ARM_SMMU_FEAT_TRANS_NESTED))) {
+ dev_err(smmu->dev, "\tno translation support!\n");
+ return -ENODEV;
+ }
+
+ if (id & ID0_CTTW) {
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+ dev_notice(smmu->dev, "\tcoherent table walk\n");
+ }
+
+ if (id & ID0_SMS) {
+ u32 smr, sid, mask;
+
+ smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
+ smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) &
+ ID0_NUMSMRG_MASK;
+ if (smmu->num_mapping_groups == 0) {
+ dev_err(smmu->dev,
+ "stream-matching supported, but no SMRs present!\n");
+ return -ENODEV;
+ }
+
+ smr = SMR_MASK_MASK << SMR_MASK_SHIFT;
+ smr |= (SMR_ID_MASK << SMR_ID_SHIFT);
+ writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
+ smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
+
+ mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
+ sid = (smr >> SMR_ID_SHIFT) & SMR_ID_MASK;
+ if ((mask & sid) != sid) {
+ dev_err(smmu->dev,
+ "SMR mask bits (0x%x) insufficient for ID field (0x%x)\n",
+ mask, sid);
+ return -ENODEV;
+ }
+
+ dev_notice(smmu->dev,
+ "\tstream matching with %u register groups, mask 0x%x",
+ smmu->num_mapping_groups, mask);
+ }
+
+ /* ID1 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1);
+ smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K;
+
+ /* Check that we ioremapped enough */
+ size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
+ size *= (smmu->pagesize << 1);
+ if (smmu->size < size)
+ dev_warn(smmu->dev,
+ "device is 0x%lx bytes but only mapped 0x%lx!\n",
+ size, smmu->size);
+
+ smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) &
+ ID1_NUMS2CB_MASK;
+ smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK;
+ if (smmu->num_s2_context_banks > smmu->num_context_banks) {
+ dev_err(smmu->dev, "impossible number of S2 context banks!\n");
+ return -ENODEV;
+ }
+ dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
+ smmu->num_context_banks, smmu->num_s2_context_banks);
+
+ /* ID2 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
+ size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
+
+ /*
+ * Stage-1 output limited by stage-2 input size due to pgd
+ * allocation (PTRS_PER_PGD).
+ */
+#ifdef CONFIG_64BIT
+ /* Current maximum output size of 39 bits */
+ smmu->s1_output_size = min(39UL, size);
+#else
+ smmu->s1_output_size = min(32UL, size);
+#endif
+
+ /* The stage-2 output mask is also applied for bypass */
+ size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
+ smmu->s2_output_size = min((unsigned long)PHYS_MASK_SHIFT, size);
+
+ if (smmu->version == 1) {
+ smmu->input_size = 32;
+ } else {
+#ifdef CONFIG_64BIT
+ size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
+ size = min(39, arm_smmu_id_size_to_bits(size));
+#else
+ size = 32;
+#endif
+ smmu->input_size = size;
+
+ if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
+ (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
+ (PAGE_SIZE != SZ_4K && PAGE_SIZE != SZ_64K)) {
+ dev_err(smmu->dev, "CPU page size 0x%lx unsupported\n",
+ PAGE_SIZE);
+ return -ENODEV;
+ }
+ }
+
+ dev_notice(smmu->dev,
+ "\t%lu-bit VA, %lu-bit IPA, %lu-bit PA\n",
+ smmu->input_size, smmu->s1_output_size, smmu->s2_output_size);
+ return 0;
+}
+
+static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device_node *dev_node;
+ struct device *dev = &pdev->dev;
+ struct rb_node *node;
+ struct of_phandle_args masterspec;
+ int num_irqs, i, err;
+
+ smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+ if (!smmu) {
+ dev_err(dev, "failed to allocate arm_smmu_device\n");
+ return -ENOMEM;
+ }
+ smmu->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing base address/size\n");
+ return -ENODEV;
+ }
+
+ smmu->size = resource_size(res);
+ smmu->base = devm_request_and_ioremap(dev, res);
+ if (!smmu->base)
+ return -EADDRNOTAVAIL;
+
+ if (of_property_read_u32(dev->of_node, "#global-interrupts",
+ &smmu->num_global_irqs)) {
+ dev_err(dev, "missing #global-interrupts property\n");
+ return -ENODEV;
+ }
+
+ num_irqs = 0;
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
+ num_irqs++;
+ if (num_irqs > smmu->num_global_irqs)
+ smmu->num_context_irqs++;
+ }
+
+ if (num_irqs < smmu->num_global_irqs) {
+ dev_warn(dev, "found %d interrupts but expected at least %d\n",
+ num_irqs, smmu->num_global_irqs);
+ smmu->num_global_irqs = num_irqs;
+ }
+ smmu->num_context_irqs = num_irqs - smmu->num_global_irqs;
+
+ smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs,
+ GFP_KERNEL);
+ if (!smmu->irqs) {
+ dev_err(dev, "failed to allocate %d irqs\n", num_irqs);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_irqs; ++i) {
+ int irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ dev_err(dev, "failed to get irq index %d\n", i);
+ return -ENODEV;
+ }
+ smmu->irqs[i] = irq;
+ }
+
+ i = 0;
+ smmu->masters = RB_ROOT;
+ while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
+ "#stream-id-cells", i,
+ &masterspec)) {
+ err = register_smmu_master(smmu, dev, &masterspec);
+ if (err) {
+ dev_err(dev, "failed to add master %s\n",
+ masterspec.np->name);
+ goto out_put_masters;
+ }
+
+ i++;
+ }
+ dev_notice(dev, "registered %d master devices\n", i);
+
+ if ((dev_node = of_parse_phandle(dev->of_node, "smmu-parent", 0)))
+ smmu->parent_of_node = dev_node;
+
+ err = arm_smmu_device_cfg_probe(smmu);
+ if (err)
+ goto out_put_parent;
+
+ if (smmu->version > 1 &&
+ smmu->num_context_banks != smmu->num_context_irqs) {
+ dev_err(dev,
+ "found only %d context interrupt(s) but %d required\n",
+ smmu->num_context_irqs, smmu->num_context_banks);
+ goto out_put_parent;
+ }
+
+ arm_smmu_device_reset(smmu);
+
+ for (i = 0; i < smmu->num_global_irqs; ++i) {
+ err = request_irq(smmu->irqs[i],
+ arm_smmu_global_fault,
+ IRQF_SHARED,
+ "arm-smmu global fault",
+ smmu);
+ if (err) {
+ dev_err(dev, "failed to request global IRQ %d (%u)\n",
+ i, smmu->irqs[i]);
+ goto out_free_irqs;
+ }
+ }
+
+ INIT_LIST_HEAD(&smmu->list);
+ spin_lock(&arm_smmu_devices_lock);
+ list_add(&smmu->list, &arm_smmu_devices);
+ spin_unlock(&arm_smmu_devices_lock);
+ return 0;
+
+out_free_irqs:
+ while (i--)
+ free_irq(smmu->irqs[i], smmu);
+
+out_put_parent:
+ if (smmu->parent_of_node)
+ of_node_put(smmu->parent_of_node);
+
+out_put_masters:
+ for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+ of_node_put(master->of_node);
+ }
+
+ return err;
+}
+
+static int arm_smmu_device_remove(struct platform_device *pdev)
+{
+ int i;
+ struct device *dev = &pdev->dev;
+ struct arm_smmu_device *curr, *smmu = NULL;
+ struct rb_node *node;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(curr, &arm_smmu_devices, list) {
+ if (curr->dev == dev) {
+ smmu = curr;
+ list_del(&smmu->list);
+ break;
+ }
+ }
+ spin_unlock(&arm_smmu_devices_lock);
+
+ if (!smmu)
+ return -ENODEV;
+
+ if (smmu->parent_of_node)
+ of_node_put(smmu->parent_of_node);
+
+ for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+ of_node_put(master->of_node);
+ }
+
+ if (!bitmap_empty(smmu->vmid_map, ARM_SMMU_NUM_VMIDS))
+ dev_err(dev, "removing device with active domains!\n");
+
+ for (i = 0; i < smmu->num_global_irqs; ++i)
+ free_irq(smmu->irqs[i], smmu);
+
+ /* Turn the thing off */
+ writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id arm_smmu_of_match[] = {
+ { .compatible = "arm,smmu-v1", },
+ { .compatible = "arm,smmu-v2", },
+ { .compatible = "arm,mmu-400", },
+ { .compatible = "arm,mmu-500", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#endif
+
+static struct platform_driver arm_smmu_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "arm-smmu",
+ .of_match_table = of_match_ptr(arm_smmu_of_match),
+ },
+ .probe = arm_smmu_device_dt_probe,
+ .remove = arm_smmu_device_remove,
+};
+
+static int __init arm_smmu_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&arm_smmu_driver);
+ if (ret)
+ return ret;
+
+ /* Oh, for a proper bus abstraction */
+ if (!iommu_present(&platform_bus_type));
+ bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+
+ if (!iommu_present(&amba_bustype));
+ bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+
+ return 0;
+}
+
+static void __exit arm_smmu_exit(void)
+{
+ return platform_driver_unregister(&arm_smmu_driver);
+}
+
+module_init(arm_smmu_init);
+module_exit(arm_smmu_exit);
+
+MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index a7967ceb79e6..785675a56a10 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -309,6 +309,7 @@ parse_dmar_table(void)
struct acpi_table_dmar *dmar;
struct acpi_dmar_header *entry_header;
int ret = 0;
+ int drhd_count = 0;
/*
* Do it again, earlier dmar_tbl mapping could be mapped with
@@ -347,6 +348,7 @@ parse_dmar_table(void)
switch (entry_header->type) {
case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+ drhd_count++;
ret = dmar_parse_one_drhd(entry_header);
break;
case ACPI_DMAR_TYPE_RESERVED_MEMORY:
@@ -371,6 +373,8 @@ parse_dmar_table(void)
entry_header = ((void *)entry_header + entry_header->length);
}
+ if (drhd_count == 0)
+ pr_warn(FW_BUG "No DRHD structure found in DMAR table\n");
return ret;
}
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b4f0e28dfa41..eec0d3e04bf5 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4182,14 +4182,27 @@ static int intel_iommu_add_device(struct device *dev)
/*
* If it's a multifunction device that does not support our
- * required ACS flags, add to the same group as function 0.
+ * required ACS flags, add to the same group as lowest numbered
+ * function that also does not suport the required ACS flags.
*/
if (dma_pdev->multifunction &&
- !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
- swap_pci_ref(&dma_pdev,
- pci_get_slot(dma_pdev->bus,
- PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
- 0)));
+ !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+ u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+ for (i = 0; i < 8; i++) {
+ struct pci_dev *tmp;
+
+ tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+ if (!tmp)
+ continue;
+
+ if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+ swap_pci_ref(&dma_pdev, tmp);
+ break;
+ }
+ pci_dev_put(tmp);
+ }
+ }
/*
* Devices on the root bus go through the iommu. If that's not us,
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 5b19b2d6ec2d..f71673dbb23d 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -664,8 +664,7 @@ error:
*/
if (x2apic_present)
- WARN(1, KERN_WARNING
- "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
+ pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
return -1;
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d8f98b14e2fe..fbe9ca734f8f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -754,6 +754,38 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
}
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
+static size_t iommu_pgsize(struct iommu_domain *domain,
+ unsigned long addr_merge, size_t size)
+{
+ unsigned int pgsize_idx;
+ size_t pgsize;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by address */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
+
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
+
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
+
+ return pgsize;
+}
+
int iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
@@ -775,45 +807,18 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
* size of the smallest page supported by the hardware
*/
if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
- pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz "
- "0x%x\n", iova, (unsigned long)paddr,
- (unsigned long)size, min_pagesz);
+ pr_err("unaligned: iova 0x%lx pa 0x%pa size 0x%zx min_pagesz 0x%x\n",
+ iova, &paddr, size, min_pagesz);
return -EINVAL;
}
- pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova,
- (unsigned long)paddr, (unsigned long)size);
+ pr_debug("map: iova 0x%lx pa 0x%pa size 0x%zx\n", iova, &paddr, size);
while (size) {
- unsigned long pgsize, addr_merge = iova | paddr;
- unsigned int pgsize_idx;
-
- /* Max page size that still fits into 'size' */
- pgsize_idx = __fls(size);
-
- /* need to consider alignment requirements ? */
- if (likely(addr_merge)) {
- /* Max page size allowed by both iova and paddr */
- unsigned int align_pgsize_idx = __ffs(addr_merge);
-
- pgsize_idx = min(pgsize_idx, align_pgsize_idx);
- }
-
- /* build a mask of acceptable page sizes */
- pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
- /* throw away page sizes not supported by the hardware */
- pgsize &= domain->ops->pgsize_bitmap;
-
- /* make sure we're still sane */
- BUG_ON(!pgsize);
-
- /* pick the biggest page */
- pgsize_idx = __fls(pgsize);
- pgsize = 1UL << pgsize_idx;
+ size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
- pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
- (unsigned long)paddr, pgsize);
+ pr_debug("mapping: iova 0x%lx pa 0x%pa pgsize 0x%zx\n",
+ iova, &paddr, pgsize);
ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
if (ret)
@@ -850,27 +855,26 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
* by the hardware
*/
if (!IS_ALIGNED(iova | size, min_pagesz)) {
- pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n",
- iova, (unsigned long)size, min_pagesz);
+ pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
+ iova, size, min_pagesz);
return -EINVAL;
}
- pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova,
- (unsigned long)size);
+ pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);
/*
* Keep iterating until we either unmap 'size' bytes (or more)
* or we hit an area that isn't mapped.
*/
while (unmapped < size) {
- size_t left = size - unmapped;
+ size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
- unmapped_page = domain->ops->unmap(domain, iova, left);
+ unmapped_page = domain->ops->unmap(domain, iova, pgsize);
if (!unmapped_page)
break;
- pr_debug("unmapped: iova 0x%lx size %lx\n", iova,
- (unsigned long)unmapped_page);
+ pr_debug("unmapped: iova 0x%lx size 0x%zx\n",
+ iova, unmapped_page);
iova += unmapped_page;
unmapped += unmapped_page;
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index e02e5d71745b..0ba3766240d5 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -833,16 +833,15 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
iopgd = iopgd_offset(obj, da);
if (!iopgd_is_table(*iopgd)) {
- dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
- "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:px%08x\n",
+ obj->name, errs, da, iopgd, *iopgd);
return IRQ_NONE;
}
iopte = iopte_offset(iopgd, da);
- dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
- "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
- iopte, *iopte);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n",
+ obj->name, errs, da, iopgd, *iopgd, iopte, *iopte);
return IRQ_NONE;
}
@@ -1235,14 +1234,16 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
else if (iopte_is_large(*pte))
ret = omap_iommu_translate(*pte, da, IOLARGE_MASK);
else
- dev_err(dev, "bogus pte 0x%x, da 0x%lx", *pte, da);
+ dev_err(dev, "bogus pte 0x%x, da 0x%llx", *pte,
+ (unsigned long long)da);
} else {
if (iopgd_is_section(*pgd))
ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK);
else if (iopgd_is_super(*pgd))
ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK);
else
- dev_err(dev, "bogus pgd 0x%x, da 0x%lx", *pgd, da);
+ dev_err(dev, "bogus pgd 0x%x, da 0x%llx", *pgd,
+ (unsigned long long)da);
}
return ret;
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
index cd4ae9e5b0c6..f4003d568a92 100644
--- a/drivers/iommu/omap-iopgtable.h
+++ b/drivers/iommu/omap-iopgtable.h
@@ -95,4 +95,4 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
#define to_iommu(dev) \
- (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
+ ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)))
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index 46d875690739..d14725984153 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -102,8 +102,8 @@ static size_t sgtable_len(const struct sg_table *sgt)
}
if (i && sg->offset) {
- pr_err("%s: sg[%d] offset not allowed in internal "
- "entries\n", __func__, i);
+ pr_err("%s: sg[%d] offset not allowed in internal entries\n",
+ __func__, i);
return 0;
}
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 2065ef6a949c..e65c41a7366b 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o
obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c
new file mode 100644
index 000000000000..5552fc2bf28a
--- /dev/null
+++ b/drivers/irqchip/irq-moxart.c
@@ -0,0 +1,117 @@
+/*
+ * MOXA ART SoCs IRQ chip driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define IRQ_SOURCE_REG 0
+#define IRQ_MASK_REG 0x04
+#define IRQ_CLEAR_REG 0x08
+#define IRQ_MODE_REG 0x0c
+#define IRQ_LEVEL_REG 0x10
+#define IRQ_STATUS_REG 0x14
+
+#define FIQ_SOURCE_REG 0x20
+#define FIQ_MASK_REG 0x24
+#define FIQ_CLEAR_REG 0x28
+#define FIQ_MODE_REG 0x2c
+#define FIQ_LEVEL_REG 0x30
+#define FIQ_STATUS_REG 0x34
+
+
+struct moxart_irq_data {
+ void __iomem *base;
+ struct irq_domain *domain;
+ unsigned int interrupt_mask;
+};
+
+static struct moxart_irq_data intc;
+
+static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+{
+ u32 irqstat;
+ int hwirq;
+
+ irqstat = readl(intc.base + IRQ_STATUS_REG);
+
+ while (irqstat) {
+ hwirq = ffs(irqstat) - 1;
+ handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
+ irqstat &= ~(1 << hwirq);
+ }
+}
+
+static int __init moxart_of_intc_init(struct device_node *node,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int ret;
+ struct irq_chip_generic *gc;
+
+ intc.base = of_iomap(node, 0);
+ if (!intc.base) {
+ pr_err("%s: unable to map IC registers\n",
+ node->full_name);
+ return -EINVAL;
+ }
+
+ intc.domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops,
+ intc.base);
+ if (!intc.domain) {
+ pr_err("%s: unable to create IRQ domain\n", node->full_name);
+ return -EINVAL;
+ }
+
+ ret = irq_alloc_domain_generic_chips(intc.domain, 32, 1,
+ "MOXARTINTC", handle_edge_irq,
+ clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: could not allocate generic chip\n",
+ node->full_name);
+ irq_domain_remove(intc.domain);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "interrupt-mask",
+ &intc.interrupt_mask);
+ if (ret)
+ pr_err("%s: could not read interrupt-mask DT property\n",
+ node->full_name);
+
+ gc = irq_get_domain_generic_chip(intc.domain, 0);
+
+ gc->reg_base = intc.base;
+ gc->chip_types[0].regs.mask = IRQ_MASK_REG;
+ gc->chip_types[0].regs.ack = IRQ_CLEAR_REG;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ writel(0, intc.base + IRQ_MASK_REG);
+ writel(0xffffffff, intc.base + IRQ_CLEAR_REG);
+
+ writel(intc.interrupt_mask, intc.base + IRQ_MODE_REG);
+ writel(intc.interrupt_mask, intc.base + IRQ_LEVEL_REG);
+
+ set_handle_irq(handle_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(moxa_moxart_ic, "moxa,moxart-ic", moxart_of_intc_init);
diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
index 8d0c8b3181c5..70bdf6edb7bb 100644
--- a/drivers/irqchip/irq-nvic.c
+++ b/drivers/irqchip/irq-nvic.c
@@ -84,7 +84,7 @@ static int __init nvic_of_init(struct device_node *node,
return -ENOMEM;
}
- ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, numbanks,
+ ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, 1,
"nvic_irq", handle_fasteoi_irq,
clr, 0, IRQ_GC_INIT_MASK_CACHE);
if (ret) {
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index b66d4ae06898..a5438d889245 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -38,7 +38,7 @@ static struct irq_domain *sun4i_irq_domain;
static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
-void sun4i_irq_ack(struct irq_data *irqd)
+static void sun4i_irq_ack(struct irq_data *irqd)
{
unsigned int irq = irqd_to_hwirq(irqd);
unsigned int irq_off = irq % 32;
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index d97059550a2c..1846e7d66681 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -178,7 +178,8 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static asmlinkage
+void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
{
u32 stat, i;
int irqnr, virq;
@@ -203,7 +204,8 @@ asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
}
}
-int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
+static int __init vt8500_irq_init(struct device_node *node,
+ struct device_node *parent)
{
int irq, i;
struct device_node *np = node;
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 3bfc8f1da9fe..30b426ed744b 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -412,4 +412,18 @@ config DM_VERITY
If unsure, say N.
+config DM_SWITCH
+ tristate "Switch target support (EXPERIMENTAL)"
+ depends on BLK_DEV_DM
+ ---help---
+ This device-mapper target creates a device that supports an arbitrary
+ mapping of fixed-size regions of I/O across a fixed set of paths.
+ The path used for any specific region can be switched dynamically
+ by sending the target a message.
+
+ To compile this code as a module, choose M here: the module will
+ be called dm-switch.
+
+ If unsure, say N.
+
endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 1439fd4ad9b1..5ef78efc27f2 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o
obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o
+obj-$(CONFIG_DM_SWITCH) += dm-switch.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_PERSISTENT_DATA) += persistent-data/
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 0387e05cdb98..5227e079a6e3 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -145,6 +145,7 @@ struct dm_buffer {
unsigned long state;
unsigned long last_accessed;
struct dm_bufio_client *c;
+ struct list_head write_list;
struct bio bio;
struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS];
};
@@ -349,7 +350,7 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
if (gfp_mask & __GFP_NORETRY)
noio_flag = memalloc_noio_save();
- ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
+ ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL);
if (gfp_mask & __GFP_NORETRY)
memalloc_noio_restore(noio_flag);
@@ -630,7 +631,8 @@ static int do_io_schedule(void *word)
* - Submit our write and don't wait on it. We set B_WRITING indicating
* that there is a write in progress.
*/
-static void __write_dirty_buffer(struct dm_buffer *b)
+static void __write_dirty_buffer(struct dm_buffer *b,
+ struct list_head *write_list)
{
if (!test_bit(B_DIRTY, &b->state))
return;
@@ -639,7 +641,24 @@ static void __write_dirty_buffer(struct dm_buffer *b)
wait_on_bit_lock(&b->state, B_WRITING,
do_io_schedule, TASK_UNINTERRUPTIBLE);
- submit_io(b, WRITE, b->block, write_endio);
+ if (!write_list)
+ submit_io(b, WRITE, b->block, write_endio);
+ else
+ list_add_tail(&b->write_list, write_list);
+}
+
+static void __flush_write_list(struct list_head *write_list)
+{
+ struct blk_plug plug;
+ blk_start_plug(&plug);
+ while (!list_empty(write_list)) {
+ struct dm_buffer *b =
+ list_entry(write_list->next, struct dm_buffer, write_list);
+ list_del(&b->write_list);
+ submit_io(b, WRITE, b->block, write_endio);
+ dm_bufio_cond_resched();
+ }
+ blk_finish_plug(&plug);
}
/*
@@ -655,7 +674,7 @@ static void __make_buffer_clean(struct dm_buffer *b)
return;
wait_on_bit(&b->state, B_READING, do_io_schedule, TASK_UNINTERRUPTIBLE);
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, NULL);
wait_on_bit(&b->state, B_WRITING, do_io_schedule, TASK_UNINTERRUPTIBLE);
}
@@ -802,7 +821,8 @@ static void __free_buffer_wake(struct dm_buffer *b)
wake_up(&c->free_buffer_wait);
}
-static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
+static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait,
+ struct list_head *write_list)
{
struct dm_buffer *b, *tmp;
@@ -818,7 +838,7 @@ static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
if (no_wait && test_bit(B_WRITING, &b->state))
return;
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, write_list);
dm_bufio_cond_resched();
}
}
@@ -853,7 +873,8 @@ static void __get_memory_limit(struct dm_bufio_client *c,
* If we are over threshold_buffers, start freeing buffers.
* If we're over "limit_buffers", block until we get under the limit.
*/
-static void __check_watermark(struct dm_bufio_client *c)
+static void __check_watermark(struct dm_bufio_client *c,
+ struct list_head *write_list)
{
unsigned long threshold_buffers, limit_buffers;
@@ -872,7 +893,7 @@ static void __check_watermark(struct dm_bufio_client *c)
}
if (c->n_buffers[LIST_DIRTY] > threshold_buffers)
- __write_dirty_buffers_async(c, 1);
+ __write_dirty_buffers_async(c, 1, write_list);
}
/*
@@ -897,7 +918,8 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
*--------------------------------------------------------------*/
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
- enum new_flag nf, int *need_submit)
+ enum new_flag nf, int *need_submit,
+ struct list_head *write_list)
{
struct dm_buffer *b, *new_b = NULL;
@@ -924,7 +946,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
goto found_buffer;
}
- __check_watermark(c);
+ __check_watermark(c, write_list);
b = new_b;
b->hold_count = 1;
@@ -992,10 +1014,14 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
int need_submit;
struct dm_buffer *b;
+ LIST_HEAD(write_list);
+
dm_bufio_lock(c);
- b = __bufio_new(c, block, nf, &need_submit);
+ b = __bufio_new(c, block, nf, &need_submit, &write_list);
dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
+
if (!b)
return b;
@@ -1047,6 +1073,8 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
{
struct blk_plug plug;
+ LIST_HEAD(write_list);
+
BUG_ON(dm_bufio_in_request());
blk_start_plug(&plug);
@@ -1055,7 +1083,15 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
for (; n_blocks--; block++) {
int need_submit;
struct dm_buffer *b;
- b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+ b = __bufio_new(c, block, NF_PREFETCH, &need_submit,
+ &write_list);
+ if (unlikely(!list_empty(&write_list))) {
+ dm_bufio_unlock(c);
+ blk_finish_plug(&plug);
+ __flush_write_list(&write_list);
+ blk_start_plug(&plug);
+ dm_bufio_lock(c);
+ }
if (unlikely(b != NULL)) {
dm_bufio_unlock(c);
@@ -1069,7 +1105,6 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
goto flush_plug;
dm_bufio_lock(c);
}
-
}
dm_bufio_unlock(c);
@@ -1126,11 +1161,14 @@ EXPORT_SYMBOL_GPL(dm_bufio_mark_buffer_dirty);
void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c)
{
+ LIST_HEAD(write_list);
+
BUG_ON(dm_bufio_in_request());
dm_bufio_lock(c);
- __write_dirty_buffers_async(c, 0);
+ __write_dirty_buffers_async(c, 0, &write_list);
dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
}
EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async);
@@ -1147,8 +1185,13 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
unsigned long buffers_processed = 0;
struct dm_buffer *b, *tmp;
+ LIST_HEAD(write_list);
+
+ dm_bufio_lock(c);
+ __write_dirty_buffers_async(c, 0, &write_list);
+ dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
dm_bufio_lock(c);
- __write_dirty_buffers_async(c, 0);
again:
list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_DIRTY], lru_list) {
@@ -1274,7 +1317,7 @@ retry:
BUG_ON(!b->hold_count);
BUG_ON(test_bit(B_READING, &b->state));
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, NULL);
if (b->hold_count == 1) {
wait_on_bit(&b->state, B_WRITING,
do_io_schedule, TASK_UNINTERRUPTIBLE);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index df44b60e66f2..0df3ec085ebb 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -425,6 +425,10 @@ static bool block_size_is_power_of_two(struct cache *cache)
return cache->sectors_per_block_shift >= 0;
}
+/* gcc on ARM generates spurious references to __udivdi3 and __umoddi3 */
+#if defined(CONFIG_ARM) && __GNUC__ == 4 && __GNUC_MINOR__ <= 6
+__always_inline
+#endif
static dm_block_t block_div(dm_block_t b, uint32_t n)
{
do_div(b, n);
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 7fcf21cb4ff8..c80a0ec5f126 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -176,7 +176,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc) {
- ti->error = "Cannot allocate linear context";
+ ti->error = "Cannot allocate context";
return -ENOMEM;
}
fc->start_time = jiffies;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index aa04f0224642..f1b758675ec7 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -36,6 +36,14 @@ struct hash_cell {
struct dm_table *new_map;
};
+/*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+ int undefined__;
+};
+
struct vers_iter {
size_t param_size;
struct dm_target_versions *vers, *old_vers;
@@ -242,9 +250,10 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
return -EBUSY;
}
-static void __hash_remove(struct hash_cell *hc)
+static struct dm_table *__hash_remove(struct hash_cell *hc)
{
struct dm_table *table;
+ int srcu_idx;
/* remove from the dev hash */
list_del(&hc->uuid_list);
@@ -253,16 +262,18 @@ static void __hash_remove(struct hash_cell *hc)
dm_set_mdptr(hc->md, NULL);
mutex_unlock(&dm_hash_cells_mutex);
- table = dm_get_live_table(hc->md);
- if (table) {
+ table = dm_get_live_table(hc->md, &srcu_idx);
+ if (table)
dm_table_event(table);
- dm_table_put(table);
- }
+ dm_put_live_table(hc->md, srcu_idx);
+ table = NULL;
if (hc->new_map)
- dm_table_destroy(hc->new_map);
+ table = hc->new_map;
dm_put(hc->md);
free_cell(hc);
+
+ return table;
}
static void dm_hash_remove_all(int keep_open_devices)
@@ -270,6 +281,7 @@ static void dm_hash_remove_all(int keep_open_devices)
int i, dev_skipped;
struct hash_cell *hc;
struct mapped_device *md;
+ struct dm_table *t;
retry:
dev_skipped = 0;
@@ -287,10 +299,14 @@ retry:
continue;
}
- __hash_remove(hc);
+ t = __hash_remove(hc);
up_write(&_hash_lock);
+ if (t) {
+ dm_sync_table(md);
+ dm_table_destroy(t);
+ }
dm_put(md);
if (likely(keep_open_devices))
dm_destroy(md);
@@ -356,6 +372,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
struct dm_table *table;
struct mapped_device *md;
unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
+ int srcu_idx;
/*
* duplicate new.
@@ -418,11 +435,10 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
/*
* Wake up any dm event waiters.
*/
- table = dm_get_live_table(hc->md);
- if (table) {
+ table = dm_get_live_table(hc->md, &srcu_idx);
+ if (table)
dm_table_event(table);
- dm_table_put(table);
- }
+ dm_put_live_table(hc->md, srcu_idx);
if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -620,11 +636,14 @@ static int check_name(const char *name)
* _hash_lock without first calling dm_table_put, because dm_table_destroy
* waits for this dm_table_put and could be called under this lock.
*/
-static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
+static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
{
struct hash_cell *hc;
struct dm_table *table = NULL;
+ /* increment rcu count, we don't care about the table pointer */
+ dm_get_live_table(md, srcu_idx);
+
down_read(&_hash_lock);
hc = dm_get_mdptr(md);
if (!hc || hc->md != md) {
@@ -633,8 +652,6 @@ static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
}
table = hc->new_map;
- if (table)
- dm_table_get(table);
out:
up_read(&_hash_lock);
@@ -643,10 +660,11 @@ out:
}
static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
- struct dm_ioctl *param)
+ struct dm_ioctl *param,
+ int *srcu_idx)
{
return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
- dm_get_inactive_table(md) : dm_get_live_table(md);
+ dm_get_inactive_table(md, srcu_idx) : dm_get_live_table(md, srcu_idx);
}
/*
@@ -657,6 +675,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{
struct gendisk *disk = dm_disk(md);
struct dm_table *table;
+ int srcu_idx;
param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
DM_ACTIVE_PRESENT_FLAG);
@@ -676,26 +695,27 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
param->event_nr = dm_get_event_nr(md);
param->target_count = 0;
- table = dm_get_live_table(md);
+ table = dm_get_live_table(md, &srcu_idx);
if (table) {
if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
if (get_disk_ro(disk))
param->flags |= DM_READONLY_FLAG;
param->target_count = dm_table_get_num_targets(table);
}
- dm_table_put(table);
param->flags |= DM_ACTIVE_PRESENT_FLAG;
}
+ dm_put_live_table(md, srcu_idx);
if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
- table = dm_get_inactive_table(md);
+ int srcu_idx;
+ table = dm_get_inactive_table(md, &srcu_idx);
if (table) {
if (!(dm_table_get_mode(table) & FMODE_WRITE))
param->flags |= DM_READONLY_FLAG;
param->target_count = dm_table_get_num_targets(table);
- dm_table_put(table);
}
+ dm_put_live_table(md, srcu_idx);
}
}
@@ -796,6 +816,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
struct hash_cell *hc;
struct mapped_device *md;
int r;
+ struct dm_table *t;
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
@@ -819,9 +840,14 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
return r;
}
- __hash_remove(hc);
+ t = __hash_remove(hc);
up_write(&_hash_lock);
+ if (t) {
+ dm_sync_table(md);
+ dm_table_destroy(t);
+ }
+
if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -986,6 +1012,7 @@ static int do_resume(struct dm_ioctl *param)
old_map = dm_swap_table(md, new_map);
if (IS_ERR(old_map)) {
+ dm_sync_table(md);
dm_table_destroy(new_map);
dm_put(md);
return PTR_ERR(old_map);
@@ -1003,6 +1030,10 @@ static int do_resume(struct dm_ioctl *param)
param->flags |= DM_UEVENT_GENERATED_FLAG;
}
+ /*
+ * Since dm_swap_table synchronizes RCU, nobody should be in
+ * read-side critical section already.
+ */
if (old_map)
dm_table_destroy(old_map);
@@ -1125,6 +1156,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
int r = 0;
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1145,11 +1177,10 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
*/
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_status(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
out:
dm_put(md);
@@ -1221,7 +1252,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
{
int r;
struct hash_cell *hc;
- struct dm_table *t;
+ struct dm_table *t, *old_map = NULL;
struct mapped_device *md;
struct target_type *immutable_target_type;
@@ -1277,14 +1308,14 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
hc = dm_get_mdptr(md);
if (!hc || hc->md != md) {
DMWARN("device has been removed from the dev hash table.");
- dm_table_destroy(t);
up_write(&_hash_lock);
+ dm_table_destroy(t);
r = -ENXIO;
goto out;
}
if (hc->new_map)
- dm_table_destroy(hc->new_map);
+ old_map = hc->new_map;
hc->new_map = t;
up_write(&_hash_lock);
@@ -1292,6 +1323,11 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
out:
+ if (old_map) {
+ dm_sync_table(md);
+ dm_table_destroy(old_map);
+ }
+
dm_put(md);
return r;
@@ -1301,6 +1337,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
struct mapped_device *md;
+ struct dm_table *old_map = NULL;
down_write(&_hash_lock);
@@ -1312,7 +1349,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
}
if (hc->new_map) {
- dm_table_destroy(hc->new_map);
+ old_map = hc->new_map;
hc->new_map = NULL;
}
@@ -1321,6 +1358,10 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
__dev_status(hc->md, param);
md = hc->md;
up_write(&_hash_lock);
+ if (old_map) {
+ dm_sync_table(md);
+ dm_table_destroy(old_map);
+ }
dm_put(md);
return 0;
@@ -1370,6 +1411,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1377,11 +1419,10 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_deps(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
dm_put(md);
@@ -1396,6 +1437,7 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1403,11 +1445,10 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_status(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
dm_put(md);
@@ -1443,6 +1484,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
struct dm_target_msg *tmsg = (void *) param + param->data_start;
size_t maxlen;
char *result = get_result_buffer(param, param_size, &maxlen);
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1470,9 +1512,9 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (r <= 1)
goto out_argv;
- table = dm_get_live_table(md);
+ table = dm_get_live_table(md, &srcu_idx);
if (!table)
- goto out_argv;
+ goto out_table;
if (dm_deleting_md(md)) {
r = -ENXIO;
@@ -1491,7 +1533,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
}
out_table:
- dm_table_put(table);
+ dm_put_live_table(md, srcu_idx);
out_argv:
kfree(argv);
out:
@@ -1644,7 +1686,10 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
}
if (!dmi) {
- dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
+ unsigned noio_flag;
+ noio_flag = memalloc_noio_save();
+ dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH | __GFP_HIGHMEM, PAGE_KERNEL);
+ memalloc_noio_restore(noio_flag);
if (dmi)
*param_flags |= DM_PARAMS_VMALLOC;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index bdf26f5bd326..5adede17ddf6 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1561,7 +1561,6 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
unsigned long flags;
int r;
-again:
bdev = NULL;
mode = 0;
r = 0;
@@ -1579,7 +1578,7 @@ again:
}
if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
- r = -EAGAIN;
+ r = -ENOTCONN;
else if (!bdev)
r = -EIO;
@@ -1591,11 +1590,8 @@ again:
if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
r = scsi_verify_blk_ioctl(NULL, cmd);
- if (r == -EAGAIN && !fatal_signal_pending(current)) {
+ if (r == -ENOTCONN && !fatal_signal_pending(current))
queue_work(kmultipathd, &m->process_queued_ios);
- msleep(10);
- goto again;
- }
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
}
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
new file mode 100644
index 000000000000..ff9ac4be4721
--- /dev/null
+++ b/drivers/md/dm-switch.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2010-2012 by Dell Inc. All rights reserved.
+ * Copyright (C) 2011-2013 Red Hat, Inc.
+ *
+ * This file is released under the GPL.
+ *
+ * dm-switch is a device-mapper target that maps IO to underlying block
+ * devices efficiently when there are a large number of fixed-sized
+ * address regions but there is no simple pattern to allow for a compact
+ * mapping representation such as dm-stripe.
+ */
+
+#include <linux/device-mapper.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#define DM_MSG_PREFIX "switch"
+
+/*
+ * One region_table_slot_t holds <region_entries_per_slot> region table
+ * entries each of which is <region_table_entry_bits> in size.
+ */
+typedef unsigned long region_table_slot_t;
+
+/*
+ * A device with the offset to its start sector.
+ */
+struct switch_path {
+ struct dm_dev *dmdev;
+ sector_t start;
+};
+
+/*
+ * Context block for a dm switch device.
+ */
+struct switch_ctx {
+ struct dm_target *ti;
+
+ unsigned nr_paths; /* Number of paths in path_list. */
+
+ unsigned region_size; /* Region size in 512-byte sectors */
+ unsigned long nr_regions; /* Number of regions making up the device */
+ signed char region_size_bits; /* log2 of region_size or -1 */
+
+ unsigned char region_table_entry_bits; /* Number of bits in one region table entry */
+ unsigned char region_entries_per_slot; /* Number of entries in one region table slot */
+ signed char region_entries_per_slot_bits; /* log2 of region_entries_per_slot or -1 */
+
+ region_table_slot_t *region_table; /* Region table */
+
+ /*
+ * Array of dm devices to switch between.
+ */
+ struct switch_path path_list[0];
+};
+
+static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_paths,
+ unsigned region_size)
+{
+ struct switch_ctx *sctx;
+
+ sctx = kzalloc(sizeof(struct switch_ctx) + nr_paths * sizeof(struct switch_path),
+ GFP_KERNEL);
+ if (!sctx)
+ return NULL;
+
+ sctx->ti = ti;
+ sctx->region_size = region_size;
+
+ ti->private = sctx;
+
+ return sctx;
+}
+
+static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
+{
+ struct switch_ctx *sctx = ti->private;
+ sector_t nr_regions = ti->len;
+ sector_t nr_slots;
+
+ if (!(sctx->region_size & (sctx->region_size - 1)))
+ sctx->region_size_bits = __ffs(sctx->region_size);
+ else
+ sctx->region_size_bits = -1;
+
+ sctx->region_table_entry_bits = 1;
+ while (sctx->region_table_entry_bits < sizeof(region_table_slot_t) * 8 &&
+ (region_table_slot_t)1 << sctx->region_table_entry_bits < nr_paths)
+ sctx->region_table_entry_bits++;
+
+ sctx->region_entries_per_slot = (sizeof(region_table_slot_t) * 8) / sctx->region_table_entry_bits;
+ if (!(sctx->region_entries_per_slot & (sctx->region_entries_per_slot - 1)))
+ sctx->region_entries_per_slot_bits = __ffs(sctx->region_entries_per_slot);
+ else
+ sctx->region_entries_per_slot_bits = -1;
+
+ if (sector_div(nr_regions, sctx->region_size))
+ nr_regions++;
+
+ sctx->nr_regions = nr_regions;
+ if (sctx->nr_regions != nr_regions || sctx->nr_regions >= ULONG_MAX) {
+ ti->error = "Region table too large";
+ return -EINVAL;
+ }
+
+ nr_slots = nr_regions;
+ if (sector_div(nr_slots, sctx->region_entries_per_slot))
+ nr_slots++;
+
+ if (nr_slots > ULONG_MAX / sizeof(region_table_slot_t)) {
+ ti->error = "Region table too large";
+ return -EINVAL;
+ }
+
+ sctx->region_table = vmalloc(nr_slots * sizeof(region_table_slot_t));
+ if (!sctx->region_table) {
+ ti->error = "Cannot allocate region table";
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr,
+ unsigned long *region_index, unsigned *bit)
+{
+ if (sctx->region_entries_per_slot_bits >= 0) {
+ *region_index = region_nr >> sctx->region_entries_per_slot_bits;
+ *bit = region_nr & (sctx->region_entries_per_slot - 1);
+ } else {
+ *region_index = region_nr / sctx->region_entries_per_slot;
+ *bit = region_nr % sctx->region_entries_per_slot;
+ }
+
+ *bit *= sctx->region_table_entry_bits;
+}
+
+/*
+ * Find which path to use at given offset.
+ */
+static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
+{
+ unsigned long region_index;
+ unsigned bit, path_nr;
+ sector_t p;
+
+ p = offset;
+ if (sctx->region_size_bits >= 0)
+ p >>= sctx->region_size_bits;
+ else
+ sector_div(p, sctx->region_size);
+
+ switch_get_position(sctx, p, &region_index, &bit);
+ path_nr = (ACCESS_ONCE(sctx->region_table[region_index]) >> bit) &
+ ((1 << sctx->region_table_entry_bits) - 1);
+
+ /* This can only happen if the processor uses non-atomic stores. */
+ if (unlikely(path_nr >= sctx->nr_paths))
+ path_nr = 0;
+
+ return path_nr;
+}
+
+static void switch_region_table_write(struct switch_ctx *sctx, unsigned long region_nr,
+ unsigned value)
+{
+ unsigned long region_index;
+ unsigned bit;
+ region_table_slot_t pte;
+
+ switch_get_position(sctx, region_nr, &region_index, &bit);
+
+ pte = sctx->region_table[region_index];
+ pte &= ~((((region_table_slot_t)1 << sctx->region_table_entry_bits) - 1) << bit);
+ pte |= (region_table_slot_t)value << bit;
+ sctx->region_table[region_index] = pte;
+}
+
+/*
+ * Fill the region table with an initial round robin pattern.
+ */
+static void initialise_region_table(struct switch_ctx *sctx)
+{
+ unsigned path_nr = 0;
+ unsigned long region_nr;
+
+ for (region_nr = 0; region_nr < sctx->nr_regions; region_nr++) {
+ switch_region_table_write(sctx, region_nr, path_nr);
+ if (++path_nr >= sctx->nr_paths)
+ path_nr = 0;
+ }
+}
+
+static int parse_path(struct dm_arg_set *as, struct dm_target *ti)
+{
+ struct switch_ctx *sctx = ti->private;
+ unsigned long long start;
+ int r;
+
+ r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
+ &sctx->path_list[sctx->nr_paths].dmdev);
+ if (r) {
+ ti->error = "Device lookup failed";
+ return r;
+ }
+
+ if (kstrtoull(dm_shift_arg(as), 10, &start) || start != (sector_t)start) {
+ ti->error = "Invalid device starting offset";
+ dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+ return -EINVAL;
+ }
+
+ sctx->path_list[sctx->nr_paths].start = start;
+
+ sctx->nr_paths++;
+
+ return 0;
+}
+
+/*
+ * Destructor: Don't free the dm_target, just the ti->private data (if any).
+ */
+static void switch_dtr(struct dm_target *ti)
+{
+ struct switch_ctx *sctx = ti->private;
+
+ while (sctx->nr_paths--)
+ dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+
+ vfree(sctx->region_table);
+ kfree(sctx);
+}
+
+/*
+ * Constructor arguments:
+ * <num_paths> <region_size> <num_optional_args> [<optional_args>...]
+ * [<dev_path> <offset>]+
+ *
+ * Optional args are to allow for future extension: currently this
+ * parameter must be 0.
+ */
+static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+ static struct dm_arg _args[] = {
+ {1, (KMALLOC_MAX_SIZE - sizeof(struct switch_ctx)) / sizeof(struct switch_path), "Invalid number of paths"},
+ {1, UINT_MAX, "Invalid region size"},
+ {0, 0, "Invalid number of optional args"},
+ };
+
+ struct switch_ctx *sctx;
+ struct dm_arg_set as;
+ unsigned nr_paths, region_size, nr_optional_args;
+ int r;
+
+ as.argc = argc;
+ as.argv = argv;
+
+ r = dm_read_arg(_args, &as, &nr_paths, &ti->error);
+ if (r)
+ return -EINVAL;
+
+ r = dm_read_arg(_args + 1, &as, &region_size, &ti->error);
+ if (r)
+ return r;
+
+ r = dm_read_arg_group(_args + 2, &as, &nr_optional_args, &ti->error);
+ if (r)
+ return r;
+ /* parse optional arguments here, if we add any */
+
+ if (as.argc != nr_paths * 2) {
+ ti->error = "Incorrect number of path arguments";
+ return -EINVAL;
+ }
+
+ sctx = alloc_switch_ctx(ti, nr_paths, region_size);
+ if (!sctx) {
+ ti->error = "Cannot allocate redirection context";
+ return -ENOMEM;
+ }
+
+ r = dm_set_target_max_io_len(ti, region_size);
+ if (r)
+ goto error;
+
+ while (as.argc) {
+ r = parse_path(&as, ti);
+ if (r)
+ goto error;
+ }
+
+ r = alloc_region_table(ti, nr_paths);
+ if (r)
+ goto error;
+
+ initialise_region_table(sctx);
+
+ /* For UNMAP, sending the request down any path is sufficient */
+ ti->num_discard_bios = 1;
+
+ return 0;
+
+error:
+ switch_dtr(ti);
+
+ return r;
+}
+
+static int switch_map(struct dm_target *ti, struct bio *bio)
+{
+ struct switch_ctx *sctx = ti->private;
+ sector_t offset = dm_target_offset(ti, bio->bi_sector);
+ unsigned path_nr = switch_get_path_nr(sctx, offset);
+
+ bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev;
+ bio->bi_sector = sctx->path_list[path_nr].start + offset;
+
+ return DM_MAPIO_REMAPPED;
+}
+
+/*
+ * We need to parse hex numbers in the message as quickly as possible.
+ *
+ * This table-based hex parser improves performance.
+ * It improves a time to load 1000000 entries compared to the condition-based
+ * parser.
+ * table-based parser condition-based parser
+ * PA-RISC 0.29s 0.31s
+ * Opteron 0.0495s 0.0498s
+ */
+static const unsigned char hex_table[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+};
+
+static __always_inline unsigned long parse_hex(const char **string)
+{
+ unsigned char d;
+ unsigned long r = 0;
+
+ while ((d = hex_table[(unsigned char)**string]) < 16) {
+ r = (r << 4) | d;
+ (*string)++;
+ }
+
+ return r;
+}
+
+static int process_set_region_mappings(struct switch_ctx *sctx,
+ unsigned argc, char **argv)
+{
+ unsigned i;
+ unsigned long region_index = 0;
+
+ for (i = 1; i < argc; i++) {
+ unsigned long path_nr;
+ const char *string = argv[i];
+
+ if (*string == ':')
+ region_index++;
+ else {
+ region_index = parse_hex(&string);
+ if (unlikely(*string != ':')) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+ }
+
+ string++;
+ if (unlikely(!*string)) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+
+ path_nr = parse_hex(&string);
+ if (unlikely(*string)) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+ if (unlikely(region_index >= sctx->nr_regions)) {
+ DMWARN("invalid set_region_mappings region number: %lu >= %lu", region_index, sctx->nr_regions);
+ return -EINVAL;
+ }
+ if (unlikely(path_nr >= sctx->nr_paths)) {
+ DMWARN("invalid set_region_mappings device: %lu >= %u", path_nr, sctx->nr_paths);
+ return -EINVAL;
+ }
+
+ switch_region_table_write(sctx, region_index, path_nr);
+ }
+
+ return 0;
+}
+
+/*
+ * Messages are processed one-at-a-time.
+ *
+ * Only set_region_mappings is supported.
+ */
+static int switch_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ static DEFINE_MUTEX(message_mutex);
+
+ struct switch_ctx *sctx = ti->private;
+ int r = -EINVAL;
+
+ mutex_lock(&message_mutex);
+
+ if (!strcasecmp(argv[0], "set_region_mappings"))
+ r = process_set_region_mappings(sctx, argc, argv);
+ else
+ DMWARN("Unrecognised message received.");
+
+ mutex_unlock(&message_mutex);
+
+ return r;
+}
+
+static void switch_status(struct dm_target *ti, status_type_t type,
+ unsigned status_flags, char *result, unsigned maxlen)
+{
+ struct switch_ctx *sctx = ti->private;
+ unsigned sz = 0;
+ int path_nr;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ result[0] = '\0';
+ break;
+
+ case STATUSTYPE_TABLE:
+ DMEMIT("%u %u 0", sctx->nr_paths, sctx->region_size);
+ for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++)
+ DMEMIT(" %s %llu", sctx->path_list[path_nr].dmdev->name,
+ (unsigned long long)sctx->path_list[path_nr].start);
+ break;
+ }
+}
+
+/*
+ * Switch ioctl:
+ *
+ * Passthrough all ioctls to the path for sector 0
+ */
+static int switch_ioctl(struct dm_target *ti, unsigned cmd,
+ unsigned long arg)
+{
+ struct switch_ctx *sctx = ti->private;
+ struct block_device *bdev;
+ fmode_t mode;
+ unsigned path_nr;
+ int r = 0;
+
+ path_nr = switch_get_path_nr(sctx, 0);
+
+ bdev = sctx->path_list[path_nr].dmdev->bdev;
+ mode = sctx->path_list[path_nr].dmdev->mode;
+
+ /*
+ * Only pass ioctls through if the device sizes match exactly.
+ */
+ if (ti->len + sctx->path_list[path_nr].start != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
+ r = scsi_verify_blk_ioctl(NULL, cmd);
+
+ return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+}
+
+static int switch_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
+{
+ struct switch_ctx *sctx = ti->private;
+ int path_nr;
+ int r;
+
+ for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++) {
+ r = fn(ti, sctx->path_list[path_nr].dmdev,
+ sctx->path_list[path_nr].start, ti->len, data);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static struct target_type switch_target = {
+ .name = "switch",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = switch_ctr,
+ .dtr = switch_dtr,
+ .map = switch_map,
+ .message = switch_message,
+ .status = switch_status,
+ .ioctl = switch_ioctl,
+ .iterate_devices = switch_iterate_devices,
+};
+
+static int __init dm_switch_init(void)
+{
+ int r;
+
+ r = dm_register_target(&switch_target);
+ if (r < 0)
+ DMERR("dm_register_target() failed %d", r);
+
+ return r;
+}
+
+static void __exit dm_switch_exit(void)
+{
+ dm_unregister_target(&switch_target);
+}
+
+module_init(dm_switch_init);
+module_exit(dm_switch_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dynamic path switching target");
+MODULE_AUTHOR("Kevin D. O'Kelley <Kevin_OKelley@dell.com>");
+MODULE_AUTHOR("Narendran Ganapathy <Narendran_Ganapathy@dell.com>");
+MODULE_AUTHOR("Jim Ramsay <Jim_Ramsay@dell.com>");
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 1ff252ab7d46..f221812b7dbc 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -26,22 +26,8 @@
#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
-/*
- * The table has always exactly one reference from either mapped_device->map
- * or hash_cell->new_map. This reference is not counted in table->holders.
- * A pair of dm_create_table/dm_destroy_table functions is used for table
- * creation/destruction.
- *
- * Temporary references from the other code increase table->holders. A pair
- * of dm_table_get/dm_table_put functions is used to manipulate it.
- *
- * When the table is about to be destroyed, we wait for table->holders to
- * drop to zero.
- */
-
struct dm_table {
struct mapped_device *md;
- atomic_t holders;
unsigned type;
/* btree table */
@@ -208,7 +194,6 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
INIT_LIST_HEAD(&t->devices);
INIT_LIST_HEAD(&t->target_callbacks);
- atomic_set(&t->holders, 0);
if (!num_targets)
num_targets = KEYS_PER_NODE;
@@ -246,10 +231,6 @@ void dm_table_destroy(struct dm_table *t)
if (!t)
return;
- while (atomic_read(&t->holders))
- msleep(1);
- smp_mb();
-
/* free the indexes */
if (t->depth >= 2)
vfree(t->index[t->depth - 2]);
@@ -274,22 +255,6 @@ void dm_table_destroy(struct dm_table *t)
kfree(t);
}
-void dm_table_get(struct dm_table *t)
-{
- atomic_inc(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_get);
-
-void dm_table_put(struct dm_table *t)
-{
- if (!t)
- return;
-
- smp_mb__before_atomic_dec();
- atomic_dec(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_put);
-
/*
* Checks to see if we need to extend highs or targets.
*/
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
index b948fd864d45..4b7941db3aff 100644
--- a/drivers/md/dm-verity.c
+++ b/drivers/md/dm-verity.c
@@ -451,7 +451,7 @@ static void verity_prefetch_io(struct work_struct *work)
goto no_prefetch_cluster;
if (unlikely(cluster & (cluster - 1)))
- cluster = 1 << (fls(cluster) - 1);
+ cluster = 1 << __fls(cluster);
hash_block_start &= ~(sector_t)(cluster - 1);
hash_block_end |= cluster - 1;
@@ -695,8 +695,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
- num < 0 || num > 1) {
+ if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
+ num > 1) {
ti->error = "Invalid version";
r = -EINVAL;
goto bad;
@@ -723,7 +723,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
- v->data_dev_block_bits = ffs(num) - 1;
+ v->data_dev_block_bits = __ffs(num);
if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
!num || (num & (num - 1)) ||
@@ -733,7 +733,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
- v->hash_dev_block_bits = ffs(num) - 1;
+ v->hash_dev_block_bits = __ffs(num);
if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
(sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
@@ -812,7 +812,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
v->hash_per_block_bits =
- fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+ __fls((1 << v->hash_dev_block_bits) / v->digest_size);
v->levels = 0;
if (v->data_blocks)
@@ -831,9 +831,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
for (i = v->levels - 1; i >= 0; i--) {
sector_t s;
v->hash_level_block[i] = hash_position;
- s = verity_position_at_level(v, v->data_blocks, i);
- s = (s >> v->hash_per_block_bits) +
- !!(s & ((1 << v->hash_per_block_bits) - 1));
+ s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
+ >> ((i + 1) * v->hash_per_block_bits);
if (hash_position + s < hash_position) {
ti->error = "Hash device offset overflow";
r = -E2BIG;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index d5370a94b2c1..9e39d2b64bf8 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -117,15 +117,29 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
#define DMF_MERGE_IS_OPTIONAL 6
/*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+ int undefined__;
+};
+
+/*
* Work processed by per-device workqueue.
*/
struct mapped_device {
- struct rw_semaphore io_lock;
+ struct srcu_struct io_barrier;
struct mutex suspend_lock;
- rwlock_t map_lock;
atomic_t holders;
atomic_t open_count;
+ /*
+ * The current mapping.
+ * Use dm_get_live_table{_fast} or take suspend_lock for
+ * dereference.
+ */
+ struct dm_table *map;
+
unsigned long flags;
struct request_queue *queue;
@@ -155,11 +169,6 @@ struct mapped_device {
struct workqueue_struct *wq;
/*
- * The current mapping.
- */
- struct dm_table *map;
-
- /*
* io objects are allocated from here.
*/
mempool_t *io_pool;
@@ -386,10 +395,14 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct mapped_device *md = bdev->bd_disk->private_data;
- struct dm_table *map = dm_get_live_table(md);
+ int srcu_idx;
+ struct dm_table *map;
struct dm_target *tgt;
int r = -ENOTTY;
+retry:
+ map = dm_get_live_table(md, &srcu_idx);
+
if (!map || !dm_table_get_size(map))
goto out;
@@ -408,7 +421,12 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
r = tgt->type->ioctl(tgt, cmd, arg);
out:
- dm_table_put(map);
+ dm_put_live_table(md, srcu_idx);
+
+ if (r == -ENOTCONN) {
+ msleep(10);
+ goto retry;
+ }
return r;
}
@@ -502,20 +520,39 @@ static void queue_io(struct mapped_device *md, struct bio *bio)
/*
* Everyone (including functions in this file), should use this
* function to access the md->map field, and make sure they call
- * dm_table_put() when finished.
+ * dm_put_live_table() when finished.
*/
-struct dm_table *dm_get_live_table(struct mapped_device *md)
+struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) __acquires(md->io_barrier)
{
- struct dm_table *t;
- unsigned long flags;
+ *srcu_idx = srcu_read_lock(&md->io_barrier);
+
+ return srcu_dereference(md->map, &md->io_barrier);
+}
- read_lock_irqsave(&md->map_lock, flags);
- t = md->map;
- if (t)
- dm_table_get(t);
- read_unlock_irqrestore(&md->map_lock, flags);
+void dm_put_live_table(struct mapped_device *md, int srcu_idx) __releases(md->io_barrier)
+{
+ srcu_read_unlock(&md->io_barrier, srcu_idx);
+}
- return t;
+void dm_sync_table(struct mapped_device *md)
+{
+ synchronize_srcu(&md->io_barrier);
+ synchronize_rcu_expedited();
+}
+
+/*
+ * A fast alternative to dm_get_live_table/dm_put_live_table.
+ * The caller must not block between these two functions.
+ */
+static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) __acquires(RCU)
+{
+ rcu_read_lock();
+ return rcu_dereference(md->map);
+}
+
+static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
+{
+ rcu_read_unlock();
}
/*
@@ -1349,17 +1386,18 @@ static int __split_and_process_non_flush(struct clone_info *ci)
/*
* Entry point to split a bio into clones and submit them to the targets.
*/
-static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
+static void __split_and_process_bio(struct mapped_device *md,
+ struct dm_table *map, struct bio *bio)
{
struct clone_info ci;
int error = 0;
- ci.map = dm_get_live_table(md);
- if (unlikely(!ci.map)) {
+ if (unlikely(!map)) {
bio_io_error(bio);
return;
}
+ ci.map = map;
ci.md = md;
ci.io = alloc_io(md);
ci.io->error = 0;
@@ -1386,7 +1424,6 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
/* drop the extra reference count */
dec_pending(ci.io, error);
- dm_table_put(ci.map);
}
/*-----------------------------------------------------------------
* CRUD END
@@ -1397,7 +1434,7 @@ static int dm_merge_bvec(struct request_queue *q,
struct bio_vec *biovec)
{
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ struct dm_table *map = dm_get_live_table_fast(md);
struct dm_target *ti;
sector_t max_sectors;
int max_size = 0;
@@ -1407,7 +1444,7 @@ static int dm_merge_bvec(struct request_queue *q,
ti = dm_table_find_target(map, bvm->bi_sector);
if (!dm_target_is_valid(ti))
- goto out_table;
+ goto out;
/*
* Find maximum amount of I/O that won't need splitting
@@ -1436,10 +1473,8 @@ static int dm_merge_bvec(struct request_queue *q,
max_size = 0;
-out_table:
- dm_table_put(map);
-
out:
+ dm_put_live_table_fast(md);
/*
* Always allow an entire first page
*/
@@ -1458,8 +1493,10 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
int cpu;
+ int srcu_idx;
+ struct dm_table *map;
- down_read(&md->io_lock);
+ map = dm_get_live_table(md, &srcu_idx);
cpu = part_stat_lock();
part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
@@ -1468,7 +1505,7 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
/* if we're suspended, we have to queue this io for later */
if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) {
- up_read(&md->io_lock);
+ dm_put_live_table(md, srcu_idx);
if (bio_rw(bio) != READA)
queue_io(md, bio);
@@ -1477,8 +1514,8 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
return;
}
- __split_and_process_bio(md, bio);
- up_read(&md->io_lock);
+ __split_and_process_bio(md, map, bio);
+ dm_put_live_table(md, srcu_idx);
return;
}
@@ -1664,7 +1701,8 @@ static struct request *dm_start_request(struct mapped_device *md, struct request
static void dm_request_fn(struct request_queue *q)
{
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ int srcu_idx;
+ struct dm_table *map = dm_get_live_table(md, &srcu_idx);
struct dm_target *ti;
struct request *rq, *clone;
sector_t pos;
@@ -1719,7 +1757,7 @@ requeued:
delay_and_out:
blk_delay_queue(q, HZ / 10);
out:
- dm_table_put(map);
+ dm_put_live_table(md, srcu_idx);
}
int dm_underlying_device_busy(struct request_queue *q)
@@ -1732,14 +1770,14 @@ static int dm_lld_busy(struct request_queue *q)
{
int r;
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ struct dm_table *map = dm_get_live_table_fast(md);
if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))
r = 1;
else
r = dm_table_any_busy_target(map);
- dm_table_put(map);
+ dm_put_live_table_fast(md);
return r;
}
@@ -1751,7 +1789,7 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
struct dm_table *map;
if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
- map = dm_get_live_table(md);
+ map = dm_get_live_table_fast(md);
if (map) {
/*
* Request-based dm cares about only own queue for
@@ -1762,9 +1800,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
bdi_bits;
else
r = dm_table_any_congested(map, bdi_bits);
-
- dm_table_put(map);
}
+ dm_put_live_table_fast(md);
}
return r;
@@ -1869,12 +1906,14 @@ static struct mapped_device *alloc_dev(int minor)
if (r < 0)
goto bad_minor;
+ r = init_srcu_struct(&md->io_barrier);
+ if (r < 0)
+ goto bad_io_barrier;
+
md->type = DM_TYPE_NONE;
- init_rwsem(&md->io_lock);
mutex_init(&md->suspend_lock);
mutex_init(&md->type_lock);
spin_lock_init(&md->deferred_lock);
- rwlock_init(&md->map_lock);
atomic_set(&md->holders, 1);
atomic_set(&md->open_count, 0);
atomic_set(&md->event_nr, 0);
@@ -1937,6 +1976,8 @@ bad_thread:
bad_disk:
blk_cleanup_queue(md->queue);
bad_queue:
+ cleanup_srcu_struct(&md->io_barrier);
+bad_io_barrier:
free_minor(minor);
bad_minor:
module_put(THIS_MODULE);
@@ -1960,6 +2001,7 @@ static void free_dev(struct mapped_device *md)
bioset_free(md->bs);
blk_integrity_unregister(md->disk);
del_gendisk(md->disk);
+ cleanup_srcu_struct(&md->io_barrier);
free_minor(minor);
spin_lock(&_minor_lock);
@@ -2102,7 +2144,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
struct dm_table *old_map;
struct request_queue *q = md->queue;
sector_t size;
- unsigned long flags;
int merge_is_optional;
size = dm_table_get_size(t);
@@ -2131,9 +2172,8 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
merge_is_optional = dm_table_merge_is_optional(t);
- write_lock_irqsave(&md->map_lock, flags);
old_map = md->map;
- md->map = t;
+ rcu_assign_pointer(md->map, t);
md->immutable_target_type = dm_table_get_immutable_target_type(t);
dm_table_set_restrictions(t, q, limits);
@@ -2141,7 +2181,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
else
clear_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
- write_unlock_irqrestore(&md->map_lock, flags);
+ dm_sync_table(md);
return old_map;
}
@@ -2152,15 +2192,13 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
static struct dm_table *__unbind(struct mapped_device *md)
{
struct dm_table *map = md->map;
- unsigned long flags;
if (!map)
return NULL;
dm_table_event_callback(map, NULL, NULL);
- write_lock_irqsave(&md->map_lock, flags);
- md->map = NULL;
- write_unlock_irqrestore(&md->map_lock, flags);
+ rcu_assign_pointer(md->map, NULL);
+ dm_sync_table(md);
return map;
}
@@ -2312,11 +2350,12 @@ EXPORT_SYMBOL_GPL(dm_device_name);
static void __dm_destroy(struct mapped_device *md, bool wait)
{
struct dm_table *map;
+ int srcu_idx;
might_sleep();
spin_lock(&_minor_lock);
- map = dm_get_live_table(md);
+ map = dm_get_live_table(md, &srcu_idx);
idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
set_bit(DMF_FREEING, &md->flags);
spin_unlock(&_minor_lock);
@@ -2326,6 +2365,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
dm_table_postsuspend_targets(map);
}
+ /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
+ dm_put_live_table(md, srcu_idx);
+
/*
* Rare, but there may be I/O requests still going to complete,
* for example. Wait for all references to disappear.
@@ -2340,7 +2382,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
dm_device_name(md), atomic_read(&md->holders));
dm_sysfs_exit(md);
- dm_table_put(map);
dm_table_destroy(__unbind(md));
free_dev(md);
}
@@ -2397,8 +2438,10 @@ static void dm_wq_work(struct work_struct *work)
struct mapped_device *md = container_of(work, struct mapped_device,
work);
struct bio *c;
+ int srcu_idx;
+ struct dm_table *map;
- down_read(&md->io_lock);
+ map = dm_get_live_table(md, &srcu_idx);
while (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
spin_lock_irq(&md->deferred_lock);
@@ -2408,17 +2451,13 @@ static void dm_wq_work(struct work_struct *work)
if (!c)
break;
- up_read(&md->io_lock);
-
if (dm_request_based(md))
generic_make_request(c);
else
- __split_and_process_bio(md, c);
-
- down_read(&md->io_lock);
+ __split_and_process_bio(md, map, c);
}
- up_read(&md->io_lock);
+ dm_put_live_table(md, srcu_idx);
}
static void dm_queue_flush(struct mapped_device *md)
@@ -2450,10 +2489,10 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
* reappear.
*/
if (dm_table_has_no_data_devices(table)) {
- live_map = dm_get_live_table(md);
+ live_map = dm_get_live_table_fast(md);
if (live_map)
limits = md->queue->limits;
- dm_table_put(live_map);
+ dm_put_live_table_fast(md);
}
if (!live_map) {
@@ -2533,7 +2572,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
goto out_unlock;
}
- map = dm_get_live_table(md);
+ map = md->map;
/*
* DMF_NOFLUSH_SUSPENDING must be set before presuspend.
@@ -2554,7 +2593,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
if (!noflush && do_lockfs) {
r = lock_fs(md);
if (r)
- goto out;
+ goto out_unlock;
}
/*
@@ -2569,9 +2608,8 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
* (dm_wq_work), we set BMF_BLOCK_IO_FOR_SUSPEND and call
* flush_workqueue(md->wq).
*/
- down_write(&md->io_lock);
set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
- up_write(&md->io_lock);
+ synchronize_srcu(&md->io_barrier);
/*
* Stop md->queue before flushing md->wq in case request-based
@@ -2589,10 +2627,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
*/
r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
- down_write(&md->io_lock);
if (noflush)
clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
- up_write(&md->io_lock);
+ synchronize_srcu(&md->io_barrier);
/* were we interrupted ? */
if (r < 0) {
@@ -2602,7 +2639,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
start_queue(md->queue);
unlock_fs(md);
- goto out; /* pushback list is already flushed, so skip flush */
+ goto out_unlock; /* pushback list is already flushed, so skip flush */
}
/*
@@ -2615,9 +2652,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
dm_table_postsuspend_targets(map);
-out:
- dm_table_put(map);
-
out_unlock:
mutex_unlock(&md->suspend_lock);
return r;
@@ -2632,7 +2666,7 @@ int dm_resume(struct mapped_device *md)
if (!dm_suspended_md(md))
goto out;
- map = dm_get_live_table(md);
+ map = md->map;
if (!map || !dm_table_get_size(map))
goto out;
@@ -2656,7 +2690,6 @@ int dm_resume(struct mapped_device *md)
r = 0;
out:
- dm_table_put(map);
mutex_unlock(&md->suspend_lock);
return r;
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index fe907f2e8f59..30779498c173 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -1,7 +1,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/saa7146_vv.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <linux/module.h>
@@ -988,26 +987,6 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
return err;
}
-static int vidioc_g_chip_ident(struct file *file, void *__fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct saa7146_fh *fh = __fh;
- struct saa7146_dev *dev = fh->dev;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match))
- chip->ident = V4L2_IDENT_SAA7146;
- return 0;
- }
- if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
- chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
- return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
- core, g_chip_ident, chip);
-}
-
const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
@@ -1018,7 +997,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_overlay = vidioc_overlay,
.vidioc_g_fbuf = vidioc_g_fbuf,
@@ -1039,7 +1017,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 45ac9eea4882..a142f7942a01 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -1154,7 +1154,7 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
char *fw_filename = smscore_get_fw_filename(coredev, mode);
if (!fw_filename) {
- sms_info("mode %d not supported on this device", mode);
+ sms_err("mode %d not supported on this device", mode);
return -ENOENT;
}
sms_debug("Firmware name: %s", fw_filename);
@@ -1165,23 +1165,24 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
rc = request_firmware(&fw, fw_filename, coredev->device);
if (rc < 0) {
- sms_info("failed to open \"%s\"", fw_filename);
+ sms_err("failed to open firmware file \"%s\"", fw_filename);
return rc;
}
sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
GFP_KERNEL | GFP_DMA);
if (!fw_buf) {
- sms_info("failed to allocate firmware buffer");
- return -ENOMEM;
- }
- memcpy(fw_buf, fw->data, fw->size);
- fw_buf_size = fw->size;
+ sms_err("failed to allocate firmware buffer");
+ rc = -ENOMEM;
+ } else {
+ memcpy(fw_buf, fw->data, fw->size);
+ fw_buf_size = fw->size;
- rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
- smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
- : loadfirmware_handler(coredev->context, fw_buf,
- fw_buf_size);
+ rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+ smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+ : loadfirmware_handler(coredev->context, fw_buf,
+ fw_buf_size);
+ }
kfree(fw_buf);
release_firmware(fw);
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index 297f1b2f9a32..086262252230 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -140,6 +140,7 @@ static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
case DEVICE_MODE_ISDBT:
case DEVICE_MODE_ISDBT_BDA:
n_layers = 4;
+ break;
default:
n_layers = 1;
}
diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c
index cc1e172dfece..c7dace671a9d 100644
--- a/drivers/media/common/tveeprom.c
+++ b/drivers/media/common/tveeprom.c
@@ -40,7 +40,6 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
MODULE_AUTHOR("John Klar");
@@ -67,13 +66,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
* The Hauppauge eeprom uses an 8bit field to determine which
* tuner formats the tuner supports.
*/
-static struct HAUPPAUGE_TUNER_FMT
-{
+static const struct {
int id;
- char *name;
-}
-hauppauge_tuner_fmt[] =
-{
+ const char * const name;
+} hauppauge_tuner_fmt[] = {
{ V4L2_STD_UNKNOWN, " UNKNOWN" },
{ V4L2_STD_UNKNOWN, " FM" },
{ V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" },
@@ -88,13 +84,10 @@ hauppauge_tuner_fmt[] =
supplying this information. Note that many tuners where only used for
testing and never made it to the outside world. So you will only see
a subset in actual produced cards. */
-static struct HAUPPAUGE_TUNER
-{
+static const struct {
int id;
- char *name;
-}
-hauppauge_tuner[] =
-{
+ const char * const name;
+} hauppauge_tuner[] = {
/* 0-9 */
{ TUNER_ABSENT, "None" },
{ TUNER_ABSENT, "External" },
@@ -298,69 +291,66 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "NXP 18272S"},
};
-/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
+/* Use TVEEPROM_AUDPROC_INTERNAL for those audio 'chips' that are
* internal to a video chip, i.e. not a separate audio chip. */
-static struct HAUPPAUGE_AUDIOIC
-{
+static const struct {
u32 id;
- char *name;
-}
-audioIC[] =
-{
+ const char * const name;
+} audio_ic[] = {
/* 0-4 */
- { V4L2_IDENT_NONE, "None" },
- { V4L2_IDENT_UNKNOWN, "TEA6300" },
- { V4L2_IDENT_UNKNOWN, "TEA6320" },
- { V4L2_IDENT_UNKNOWN, "TDA9850" },
- { V4L2_IDENT_MSPX4XX, "MSP3400C" },
+ { TVEEPROM_AUDPROC_NONE, "None" },
+ { TVEEPROM_AUDPROC_OTHER, "TEA6300" },
+ { TVEEPROM_AUDPROC_OTHER, "TEA6320" },
+ { TVEEPROM_AUDPROC_OTHER, "TDA9850" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3400C" },
/* 5-9 */
- { V4L2_IDENT_MSPX4XX, "MSP3410D" },
- { V4L2_IDENT_MSPX4XX, "MSP3415" },
- { V4L2_IDENT_MSPX4XX, "MSP3430" },
- { V4L2_IDENT_MSPX4XX, "MSP3438" },
- { V4L2_IDENT_UNKNOWN, "CS5331" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3410D" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3415" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3430" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3438" },
+ { TVEEPROM_AUDPROC_OTHER, "CS5331" },
/* 10-14 */
- { V4L2_IDENT_MSPX4XX, "MSP3435" },
- { V4L2_IDENT_MSPX4XX, "MSP3440" },
- { V4L2_IDENT_MSPX4XX, "MSP3445" },
- { V4L2_IDENT_MSPX4XX, "MSP3411" },
- { V4L2_IDENT_MSPX4XX, "MSP3416" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3435" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3440" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3445" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3411" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3416" },
/* 15-19 */
- { V4L2_IDENT_MSPX4XX, "MSP3425" },
- { V4L2_IDENT_MSPX4XX, "MSP3451" },
- { V4L2_IDENT_MSPX4XX, "MSP3418" },
- { V4L2_IDENT_UNKNOWN, "Type 0x12" },
- { V4L2_IDENT_UNKNOWN, "OKI7716" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3425" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3451" },
+ { TVEEPROM_AUDPROC_MSP, "MSP3418" },
+ { TVEEPROM_AUDPROC_OTHER, "Type 0x12" },
+ { TVEEPROM_AUDPROC_OTHER, "OKI7716" },
/* 20-24 */
- { V4L2_IDENT_MSPX4XX, "MSP4410" },
- { V4L2_IDENT_MSPX4XX, "MSP4420" },
- { V4L2_IDENT_MSPX4XX, "MSP4440" },
- { V4L2_IDENT_MSPX4XX, "MSP4450" },
- { V4L2_IDENT_MSPX4XX, "MSP4408" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4410" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4420" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4440" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4450" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4408" },
/* 25-29 */
- { V4L2_IDENT_MSPX4XX, "MSP4418" },
- { V4L2_IDENT_MSPX4XX, "MSP4428" },
- { V4L2_IDENT_MSPX4XX, "MSP4448" },
- { V4L2_IDENT_MSPX4XX, "MSP4458" },
- { V4L2_IDENT_MSPX4XX, "Type 0x1d" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4418" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4428" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4448" },
+ { TVEEPROM_AUDPROC_MSP, "MSP4458" },
+ { TVEEPROM_AUDPROC_MSP, "Type 0x1d" },
/* 30-34 */
- { V4L2_IDENT_AMBIGUOUS, "CX880" },
- { V4L2_IDENT_AMBIGUOUS, "CX881" },
- { V4L2_IDENT_AMBIGUOUS, "CX883" },
- { V4L2_IDENT_AMBIGUOUS, "CX882" },
- { V4L2_IDENT_AMBIGUOUS, "CX25840" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX880" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX881" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX883" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX882" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX25840" },
/* 35-39 */
- { V4L2_IDENT_AMBIGUOUS, "CX25841" },
- { V4L2_IDENT_AMBIGUOUS, "CX25842" },
- { V4L2_IDENT_AMBIGUOUS, "CX25843" },
- { V4L2_IDENT_AMBIGUOUS, "CX23418" },
- { V4L2_IDENT_AMBIGUOUS, "CX23885" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX25841" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX25842" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX25843" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX23418" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX23885" },
/* 40-44 */
- { V4L2_IDENT_AMBIGUOUS, "CX23888" },
- { V4L2_IDENT_AMBIGUOUS, "SAA7131" },
- { V4L2_IDENT_AMBIGUOUS, "CX23887" },
- { V4L2_IDENT_AMBIGUOUS, "SAA7164" },
- { V4L2_IDENT_AMBIGUOUS, "AU8522" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX23888" },
+ { TVEEPROM_AUDPROC_INTERNAL, "SAA7131" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX23887" },
+ { TVEEPROM_AUDPROC_INTERNAL, "SAA7164" },
+ { TVEEPROM_AUDPROC_INTERNAL, "AU8522" },
};
/* This list is supplied by Hauppauge. Thanks! */
@@ -453,11 +443,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
int i, j, len, done, beenhere, tag, start;
int tuner1 = 0, t_format1 = 0, audioic = -1;
- char *t_name1 = NULL;
+ const char *t_name1 = NULL;
const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
int tuner2 = 0, t_format2 = 0;
- char *t_name2 = NULL;
+ const char *t_name2 = NULL;
const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
memset(tvee, 0, sizeof(*tvee));
@@ -545,10 +535,10 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+2] & 0x7f;
- if (audioic < ARRAY_SIZE(audioIC))
- tvee->audio_processor = audioIC[audioic].id;
+ if (audioic < ARRAY_SIZE(audio_ic))
+ tvee->audio_processor = audio_ic[audioic].id;
else
- tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+ tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
break;
/* case 0x03: tag 'EEInfo' */
@@ -578,10 +568,10 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+1] & 0x7f;
- if (audioic < ARRAY_SIZE(audioIC))
- tvee->audio_processor = audioIC[audioic].id;
+ if (audioic < ARRAY_SIZE(audio_ic))
+ tvee->audio_processor = audio_ic[audioic].id;
else
- tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+ tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
break;
@@ -726,11 +716,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
t_fmt_name2[6], t_fmt_name2[7], t_format2);
if (audioic < 0) {
tveeprom_info("audio processor is unknown (no idx)\n");
- tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+ tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
} else {
- if (audioic < ARRAY_SIZE(audioIC))
+ if (audioic < ARRAY_SIZE(audio_ic))
tveeprom_info("audio processor is %s (idx %d)\n",
- audioIC[audioic].name, audioic);
+ audio_ic[audioic].name, audioic);
else
tveeprom_info("audio processor is unknown (idx %d)\n",
audioic);
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index a1a3a5159d71..0b4616b87195 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -377,10 +377,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
buffer2_len);
}
- if (ret < 0) {
- dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ if (ret < 0)
dmxdevfilter->buffer.error = ret;
- }
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock);
@@ -416,10 +414,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
- if (ret < 0) {
- dvb_ringbuffer_flush(buffer);
+ if (ret < 0)
buffer->error = ret;
- }
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 335a8f4695b4..886da16e14f2 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -367,4 +367,6 @@
#define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002
#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004
#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500
+#define USB_PID_CPYTO_REDI_PC50A 0xa803
+#define USB_PID_CTVDIGDUAL_V2 0xe410
#endif
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index 2099f21e374d..23a0d05ba426 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -35,7 +35,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-device.h>
#include "au8522.h"
#include "au8522_priv.h"
@@ -524,13 +523,8 @@ static int au8522_s_ctrl(struct v4l2_ctrl *ctrl)
static int au8522_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct au8522_state *state = to_state(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = au8522_readreg(state, reg->reg & 0xffff);
return 0;
}
@@ -538,13 +532,8 @@ static int au8522_g_register(struct v4l2_subdev *sd,
static int au8522_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct au8522_state *state = to_state(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
au8522_writereg(state, reg->reg, reg->val & 0xff);
return 0;
}
@@ -636,20 +625,10 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int au8522_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct au8522_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops au8522_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .g_chip_ident = au8522_g_chip_ident,
.reset = au8522_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = au8522_g_register,
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index a54182dd0e91..90536147bf04 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -3406,7 +3406,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
- int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER;
+ int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
u8 exit_condition, index_frontend;
u32 delay, callback_time;
@@ -3553,7 +3553,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
}
}
- return ret;
+ return 0;
}
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
index e6667189ddce..f22eb9f13ad5 100644
--- a/drivers/media/dvb-frontends/drxk.h
+++ b/drivers/media/dvb-frontends/drxk.h
@@ -8,7 +8,7 @@
/**
* struct drxk_config - Configure the initial parameters for DRX-K
*
- * @adr: I2C Address of the DRX-K
+ * @adr: I2C address of the DRX-K
* @parallel_ts: True means that the device uses parallel TS,
* Serial otherwise.
* @dynamic_clk: True means that the clock will be dynamically
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index ec24d71e153d..082014de6875 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -21,6 +21,8 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -34,35 +36,36 @@
#include "dvb_frontend.h"
#include "drxk.h"
#include "drxk_hard.h"
-
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
-static int PowerDownQAM(struct drxk_state *state);
-static int SetDVBTStandard(struct drxk_state *state,
- enum OperationMode oMode);
-static int SetQAMStandard(struct drxk_state *state,
- enum OperationMode oMode);
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
- s32 tunerFreqOffset);
-static int SetDVBTStandard(struct drxk_state *state,
- enum OperationMode oMode);
-static int DVBTStart(struct drxk_state *state);
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
- s32 tunerFreqOffset);
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int SwitchAntennaToQAM(struct drxk_state *state);
-static int SwitchAntennaToDVBT(struct drxk_state *state);
-
-static bool IsDVBT(struct drxk_state *state)
+#include "dvb_math.h"
+
+static int power_down_dvbt(struct drxk_state *state, bool set_power_mode);
+static int power_down_qam(struct drxk_state *state);
+static int set_dvbt_standard(struct drxk_state *state,
+ enum operation_mode o_mode);
+static int set_qam_standard(struct drxk_state *state,
+ enum operation_mode o_mode);
+static int set_qam(struct drxk_state *state, u16 intermediate_freqk_hz,
+ s32 tuner_freq_offset);
+static int set_dvbt_standard(struct drxk_state *state,
+ enum operation_mode o_mode);
+static int dvbt_start(struct drxk_state *state);
+static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
+ s32 tuner_freq_offset);
+static int get_qam_lock_status(struct drxk_state *state, u32 *p_lock_status);
+static int get_dvbt_lock_status(struct drxk_state *state, u32 *p_lock_status);
+static int switch_antenna_to_qam(struct drxk_state *state);
+static int switch_antenna_to_dvbt(struct drxk_state *state);
+
+static bool is_dvbt(struct drxk_state *state)
{
- return state->m_OperationMode == OM_DVBT;
+ return state->m_operation_mode == OM_DVBT;
}
-static bool IsQAM(struct drxk_state *state)
+static bool is_qam(struct drxk_state *state)
{
- return state->m_OperationMode == OM_QAM_ITU_A ||
- state->m_OperationMode == OM_QAM_ITU_B ||
- state->m_OperationMode == OM_QAM_ITU_C;
+ return state->m_operation_mode == OM_QAM_ITU_A ||
+ state->m_operation_mode == OM_QAM_ITU_B ||
+ state->m_operation_mode == OM_QAM_ITU_C;
}
#define NOA1ROM 0
@@ -165,7 +168,7 @@ MODULE_PARM_DESC(debug, "enable debug messages");
#define dprintk(level, fmt, arg...) do { \
if (debug >= level) \
- printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg); \
+ pr_debug(fmt, ##arg); \
} while (0)
@@ -186,8 +189,10 @@ static inline u32 Frac28a(u32 a, u32 c)
u32 R0 = 0;
R0 = (a % c) << 4; /* 32-28 == 4 shifts possible at max */
- Q1 = a / c; /* integer part, only the 4 least significant bits
- will be visible in the result */
+ Q1 = a / c; /*
+ * integer part, only the 4 least significant
+ * bits will be visible in the result
+ */
/* division using radix 16, 7 nibbles in the result */
for (i = 0; i < 7; i++) {
@@ -201,98 +206,9 @@ static inline u32 Frac28a(u32 a, u32 c)
return Q1;
}
-static u32 Log10Times100(u32 x)
+static inline u32 log10times100(u32 value)
{
- static const u8 scale = 15;
- static const u8 indexWidth = 5;
- u8 i = 0;
- u32 y = 0;
- u32 d = 0;
- u32 k = 0;
- u32 r = 0;
- /*
- log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
- 0 <= n < ((1<<INDEXWIDTH)+1)
- */
-
- static const u32 log2lut[] = {
- 0, /* 0.000000 */
- 290941, /* 290941.300628 */
- 573196, /* 573196.476418 */
- 847269, /* 847269.179851 */
- 1113620, /* 1113620.489452 */
- 1372674, /* 1372673.576986 */
- 1624818, /* 1624817.752104 */
- 1870412, /* 1870411.981536 */
- 2109788, /* 2109787.962654 */
- 2343253, /* 2343252.817465 */
- 2571091, /* 2571091.461923 */
- 2793569, /* 2793568.696416 */
- 3010931, /* 3010931.055901 */
- 3223408, /* 3223408.452106 */
- 3431216, /* 3431215.635215 */
- 3634553, /* 3634553.498355 */
- 3833610, /* 3833610.244726 */
- 4028562, /* 4028562.434393 */
- 4219576, /* 4219575.925308 */
- 4406807, /* 4406806.721144 */
- 4590402, /* 4590401.736809 */
- 4770499, /* 4770499.491025 */
- 4947231, /* 4947230.734179 */
- 5120719, /* 5120719.018555 */
- 5291081, /* 5291081.217197 */
- 5458428, /* 5458427.996830 */
- 5622864, /* 5622864.249668 */
- 5784489, /* 5784489.488298 */
- 5943398, /* 5943398.207380 */
- 6099680, /* 6099680.215452 */
- 6253421, /* 6253420.939751 */
- 6404702, /* 6404701.706649 */
- 6553600, /* 6553600.000000 */
- };
-
-
- if (x == 0)
- return 0;
-
- /* Scale x (normalize) */
- /* computing y in log(x/y) = log(x) - log(y) */
- if ((x & ((0xffffffff) << (scale + 1))) == 0) {
- for (k = scale; k > 0; k--) {
- if (x & (((u32) 1) << scale))
- break;
- x <<= 1;
- }
- } else {
- for (k = scale; k < 31; k++) {
- if ((x & (((u32) (-1)) << (scale + 1))) == 0)
- break;
- x >>= 1;
- }
- }
- /*
- Now x has binary point between bit[scale] and bit[scale-1]
- and 1.0 <= x < 2.0 */
-
- /* correction for divison: log(x) = log(x/y)+log(y) */
- y = k * ((((u32) 1) << scale) * 200);
-
- /* remove integer part */
- x &= ((((u32) 1) << scale) - 1);
- /* get index */
- i = (u8) (x >> (scale - indexWidth));
- /* compute delta (x - a) */
- d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
- /* compute log, multiplication (d* (..)) must be within range ! */
- y += log2lut[i] +
- ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
- /* Conver to log10() */
- y /= 108853; /* (log2(10) << scale) */
- r = (y >> 1);
- /* rounding */
- if (y & ((u32) 1))
- r++;
- return r;
+ return (100L * intlog10(value)) >> 24;
}
/****************************************************************************/
@@ -344,15 +260,15 @@ static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
if (debug > 2) {
int i;
for (i = 0; i < len; i++)
- printk(KERN_CONT " %02x", data[i]);
- printk(KERN_CONT "\n");
+ pr_cont(" %02x", data[i]);
+ pr_cont("\n");
}
status = drxk_i2c_transfer(state, &msg, 1);
if (status >= 0 && status != 1)
status = -EIO;
if (status < 0)
- printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
+ pr_err("i2c write error at addr 0x%02x\n", adr);
return status;
}
@@ -371,22 +287,22 @@ static int i2c_read(struct drxk_state *state,
status = drxk_i2c_transfer(state, msgs, 2);
if (status != 2) {
if (debug > 2)
- printk(KERN_CONT ": ERROR!\n");
+ pr_cont(": ERROR!\n");
if (status >= 0)
status = -EIO;
- printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
+ pr_err("i2c read error at addr 0x%02x\n", adr);
return status;
}
if (debug > 2) {
int i;
dprintk(2, ": read from");
for (i = 0; i < len; i++)
- printk(KERN_CONT " %02x", msg[i]);
- printk(KERN_CONT ", value = ");
+ pr_cont(" %02x", msg[i]);
+ pr_cont(", value = ");
for (i = 0; i < alen; i++)
- printk(KERN_CONT " %02x", answ[i]);
- printk(KERN_CONT "\n");
+ pr_cont(" %02x", answ[i]);
+ pr_cont("\n");
}
return 0;
}
@@ -520,55 +436,55 @@ static int write32(struct drxk_state *state, u32 reg, u32 data)
return write32_flags(state, reg, data, 0);
}
-static int write_block(struct drxk_state *state, u32 Address,
- const int BlockSize, const u8 pBlock[])
+static int write_block(struct drxk_state *state, u32 address,
+ const int block_size, const u8 p_block[])
{
- int status = 0, BlkSize = BlockSize;
- u8 Flags = 0;
+ int status = 0, blk_size = block_size;
+ u8 flags = 0;
if (state->single_master)
- Flags |= 0xC0;
-
- while (BlkSize > 0) {
- int Chunk = BlkSize > state->m_ChunkSize ?
- state->m_ChunkSize : BlkSize;
- u8 *AdrBuf = &state->Chunk[0];
- u32 AdrLength = 0;
-
- if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
- AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
- AdrBuf[1] = ((Address >> 16) & 0xFF);
- AdrBuf[2] = ((Address >> 24) & 0xFF);
- AdrBuf[3] = ((Address >> 7) & 0xFF);
- AdrBuf[2] |= Flags;
- AdrLength = 4;
- if (Chunk == state->m_ChunkSize)
- Chunk -= 2;
+ flags |= 0xC0;
+
+ while (blk_size > 0) {
+ int chunk = blk_size > state->m_chunk_size ?
+ state->m_chunk_size : blk_size;
+ u8 *adr_buf = &state->chunk[0];
+ u32 adr_length = 0;
+
+ if (DRXDAP_FASI_LONG_FORMAT(address) || (flags != 0)) {
+ adr_buf[0] = (((address << 1) & 0xFF) | 0x01);
+ adr_buf[1] = ((address >> 16) & 0xFF);
+ adr_buf[2] = ((address >> 24) & 0xFF);
+ adr_buf[3] = ((address >> 7) & 0xFF);
+ adr_buf[2] |= flags;
+ adr_length = 4;
+ if (chunk == state->m_chunk_size)
+ chunk -= 2;
} else {
- AdrBuf[0] = ((Address << 1) & 0xFF);
- AdrBuf[1] = (((Address >> 16) & 0x0F) |
- ((Address >> 18) & 0xF0));
- AdrLength = 2;
+ adr_buf[0] = ((address << 1) & 0xFF);
+ adr_buf[1] = (((address >> 16) & 0x0F) |
+ ((address >> 18) & 0xF0));
+ adr_length = 2;
}
- memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
- dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
+ memcpy(&state->chunk[adr_length], p_block, chunk);
+ dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
if (debug > 1) {
int i;
- if (pBlock)
- for (i = 0; i < Chunk; i++)
- printk(KERN_CONT " %02x", pBlock[i]);
- printk(KERN_CONT "\n");
+ if (p_block)
+ for (i = 0; i < chunk; i++)
+ pr_cont(" %02x", p_block[i]);
+ pr_cont("\n");
}
status = i2c_write(state, state->demod_address,
- &state->Chunk[0], Chunk + AdrLength);
+ &state->chunk[0], chunk + adr_length);
if (status < 0) {
- printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
- __func__, Address);
+ pr_err("%s: i2c write error at addr 0x%02x\n",
+ __func__, address);
break;
}
- pBlock += Chunk;
- Address += (Chunk >> 1);
- BlkSize -= Chunk;
+ p_block += chunk;
+ address += (chunk >> 1);
+ blk_size -= chunk;
}
return status;
}
@@ -577,11 +493,11 @@ static int write_block(struct drxk_state *state, u32 Address,
#define DRXK_MAX_RETRIES_POWERUP 20
#endif
-static int PowerUpDevice(struct drxk_state *state)
+static int power_up_device(struct drxk_state *state)
{
int status;
u8 data = 0;
- u16 retryCount = 0;
+ u16 retry_count = 0;
dprintk(1, "\n");
@@ -591,15 +507,15 @@ static int PowerUpDevice(struct drxk_state *state)
data = 0;
status = i2c_write(state, state->demod_address,
&data, 1);
- msleep(10);
- retryCount++;
+ usleep_range(10000, 11000);
+ retry_count++;
if (status < 0)
continue;
status = i2c_read1(state, state->demod_address,
&data);
} while (status < 0 &&
- (retryCount < DRXK_MAX_RETRIES_POWERUP));
- if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
+ (retry_count < DRXK_MAX_RETRIES_POWERUP));
+ if (status < 0 && retry_count >= DRXK_MAX_RETRIES_POWERUP)
goto error;
}
@@ -615,11 +531,11 @@ static int PowerUpDevice(struct drxk_state *state)
if (status < 0)
goto error;
- state->m_currentPowerMode = DRX_POWER_UP;
+ state->m_current_power_mode = DRX_POWER_UP;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -631,106 +547,106 @@ static int init_state(struct drxk_state *state)
* FIXME: most (all?) of the values bellow should be moved into
* struct drxk_config, as they are probably board-specific
*/
- u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
- u32 ulVSBIfAgcOutputLevel = 0;
- u32 ulVSBIfAgcMinLevel = 0;
- u32 ulVSBIfAgcMaxLevel = 0x7FFF;
- u32 ulVSBIfAgcSpeed = 3;
-
- u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
- u32 ulVSBRfAgcOutputLevel = 0;
- u32 ulVSBRfAgcMinLevel = 0;
- u32 ulVSBRfAgcMaxLevel = 0x7FFF;
- u32 ulVSBRfAgcSpeed = 3;
- u32 ulVSBRfAgcTop = 9500;
- u32 ulVSBRfAgcCutOffCurrent = 4000;
-
- u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
- u32 ulATVIfAgcOutputLevel = 0;
- u32 ulATVIfAgcMinLevel = 0;
- u32 ulATVIfAgcMaxLevel = 0;
- u32 ulATVIfAgcSpeed = 3;
-
- u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
- u32 ulATVRfAgcOutputLevel = 0;
- u32 ulATVRfAgcMinLevel = 0;
- u32 ulATVRfAgcMaxLevel = 0;
- u32 ulATVRfAgcTop = 9500;
- u32 ulATVRfAgcCutOffCurrent = 4000;
- u32 ulATVRfAgcSpeed = 3;
+ u32 ul_vsb_if_agc_mode = DRXK_AGC_CTRL_AUTO;
+ u32 ul_vsb_if_agc_output_level = 0;
+ u32 ul_vsb_if_agc_min_level = 0;
+ u32 ul_vsb_if_agc_max_level = 0x7FFF;
+ u32 ul_vsb_if_agc_speed = 3;
+
+ u32 ul_vsb_rf_agc_mode = DRXK_AGC_CTRL_AUTO;
+ u32 ul_vsb_rf_agc_output_level = 0;
+ u32 ul_vsb_rf_agc_min_level = 0;
+ u32 ul_vsb_rf_agc_max_level = 0x7FFF;
+ u32 ul_vsb_rf_agc_speed = 3;
+ u32 ul_vsb_rf_agc_top = 9500;
+ u32 ul_vsb_rf_agc_cut_off_current = 4000;
+
+ u32 ul_atv_if_agc_mode = DRXK_AGC_CTRL_AUTO;
+ u32 ul_atv_if_agc_output_level = 0;
+ u32 ul_atv_if_agc_min_level = 0;
+ u32 ul_atv_if_agc_max_level = 0;
+ u32 ul_atv_if_agc_speed = 3;
+
+ u32 ul_atv_rf_agc_mode = DRXK_AGC_CTRL_OFF;
+ u32 ul_atv_rf_agc_output_level = 0;
+ u32 ul_atv_rf_agc_min_level = 0;
+ u32 ul_atv_rf_agc_max_level = 0;
+ u32 ul_atv_rf_agc_top = 9500;
+ u32 ul_atv_rf_agc_cut_off_current = 4000;
+ u32 ul_atv_rf_agc_speed = 3;
u32 ulQual83 = DEFAULT_MER_83;
u32 ulQual93 = DEFAULT_MER_93;
- u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
- u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+ u32 ul_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+ u32 ul_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
/* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
/* io_pad_cfg_mode output mode is drive always */
/* io_pad_cfg_drive is set to power 2 (23 mA) */
- u32 ulGPIOCfg = 0x0113;
- u32 ulInvertTSClock = 0;
- u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
- u32 ulDVBTBitrate = 50000000;
- u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
+ u32 ul_gpio_cfg = 0x0113;
+ u32 ul_invert_ts_clock = 0;
+ u32 ul_ts_data_strength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
+ u32 ul_dvbt_bitrate = 50000000;
+ u32 ul_dvbc_bitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
- u32 ulInsertRSByte = 0;
+ u32 ul_insert_rs_byte = 0;
- u32 ulRfMirror = 1;
- u32 ulPowerDown = 0;
+ u32 ul_rf_mirror = 1;
+ u32 ul_power_down = 0;
dprintk(1, "\n");
- state->m_hasLNA = false;
- state->m_hasDVBT = false;
- state->m_hasDVBC = false;
- state->m_hasATV = false;
- state->m_hasOOB = false;
- state->m_hasAudio = false;
+ state->m_has_lna = false;
+ state->m_has_dvbt = false;
+ state->m_has_dvbc = false;
+ state->m_has_atv = false;
+ state->m_has_oob = false;
+ state->m_has_audio = false;
- if (!state->m_ChunkSize)
- state->m_ChunkSize = 124;
+ if (!state->m_chunk_size)
+ state->m_chunk_size = 124;
- state->m_oscClockFreq = 0;
- state->m_smartAntInverted = false;
- state->m_bPDownOpenBridge = false;
+ state->m_osc_clock_freq = 0;
+ state->m_smart_ant_inverted = false;
+ state->m_b_p_down_open_bridge = false;
/* real system clock frequency in kHz */
- state->m_sysClockFreq = 151875;
+ state->m_sys_clock_freq = 151875;
/* Timing div, 250ns/Psys */
/* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
- state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
+ state->m_hi_cfg_timing_div = ((state->m_sys_clock_freq / 1000) *
HI_I2C_DELAY) / 1000;
/* Clipping */
- if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
- state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
- state->m_HICfgWakeUpKey = (state->demod_address << 1);
+ if (state->m_hi_cfg_timing_div > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+ state->m_hi_cfg_timing_div = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+ state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
/* port/bridge/power down ctrl */
- state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+ state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
- state->m_bPowerDown = (ulPowerDown != 0);
+ state->m_b_power_down = (ul_power_down != 0);
- state->m_DRXK_A3_PATCH_CODE = false;
+ state->m_drxk_a3_patch_code = false;
/* Init AGC and PGA parameters */
/* VSB IF */
- state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
- state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
- state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
- state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
- state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
- state->m_vsbPgaCfg = 140;
+ state->m_vsb_if_agc_cfg.ctrl_mode = ul_vsb_if_agc_mode;
+ state->m_vsb_if_agc_cfg.output_level = ul_vsb_if_agc_output_level;
+ state->m_vsb_if_agc_cfg.min_output_level = ul_vsb_if_agc_min_level;
+ state->m_vsb_if_agc_cfg.max_output_level = ul_vsb_if_agc_max_level;
+ state->m_vsb_if_agc_cfg.speed = ul_vsb_if_agc_speed;
+ state->m_vsb_pga_cfg = 140;
/* VSB RF */
- state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
- state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
- state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
- state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
- state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
- state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
- state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
- state->m_vsbPreSawCfg.reference = 0x07;
- state->m_vsbPreSawCfg.usePreSaw = true;
+ state->m_vsb_rf_agc_cfg.ctrl_mode = ul_vsb_rf_agc_mode;
+ state->m_vsb_rf_agc_cfg.output_level = ul_vsb_rf_agc_output_level;
+ state->m_vsb_rf_agc_cfg.min_output_level = ul_vsb_rf_agc_min_level;
+ state->m_vsb_rf_agc_cfg.max_output_level = ul_vsb_rf_agc_max_level;
+ state->m_vsb_rf_agc_cfg.speed = ul_vsb_rf_agc_speed;
+ state->m_vsb_rf_agc_cfg.top = ul_vsb_rf_agc_top;
+ state->m_vsb_rf_agc_cfg.cut_off_current = ul_vsb_rf_agc_cut_off_current;
+ state->m_vsb_pre_saw_cfg.reference = 0x07;
+ state->m_vsb_pre_saw_cfg.use_pre_saw = true;
state->m_Quality83percent = DEFAULT_MER_83;
state->m_Quality93percent = DEFAULT_MER_93;
@@ -740,127 +656,127 @@ static int init_state(struct drxk_state *state)
}
/* ATV IF */
- state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
- state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
- state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
- state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
- state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
+ state->m_atv_if_agc_cfg.ctrl_mode = ul_atv_if_agc_mode;
+ state->m_atv_if_agc_cfg.output_level = ul_atv_if_agc_output_level;
+ state->m_atv_if_agc_cfg.min_output_level = ul_atv_if_agc_min_level;
+ state->m_atv_if_agc_cfg.max_output_level = ul_atv_if_agc_max_level;
+ state->m_atv_if_agc_cfg.speed = ul_atv_if_agc_speed;
/* ATV RF */
- state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
- state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
- state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
- state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
- state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
- state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
- state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
- state->m_atvPreSawCfg.reference = 0x04;
- state->m_atvPreSawCfg.usePreSaw = true;
+ state->m_atv_rf_agc_cfg.ctrl_mode = ul_atv_rf_agc_mode;
+ state->m_atv_rf_agc_cfg.output_level = ul_atv_rf_agc_output_level;
+ state->m_atv_rf_agc_cfg.min_output_level = ul_atv_rf_agc_min_level;
+ state->m_atv_rf_agc_cfg.max_output_level = ul_atv_rf_agc_max_level;
+ state->m_atv_rf_agc_cfg.speed = ul_atv_rf_agc_speed;
+ state->m_atv_rf_agc_cfg.top = ul_atv_rf_agc_top;
+ state->m_atv_rf_agc_cfg.cut_off_current = ul_atv_rf_agc_cut_off_current;
+ state->m_atv_pre_saw_cfg.reference = 0x04;
+ state->m_atv_pre_saw_cfg.use_pre_saw = true;
/* DVBT RF */
- state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
- state->m_dvbtRfAgcCfg.outputLevel = 0;
- state->m_dvbtRfAgcCfg.minOutputLevel = 0;
- state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
- state->m_dvbtRfAgcCfg.top = 0x2100;
- state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
- state->m_dvbtRfAgcCfg.speed = 1;
+ state->m_dvbt_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
+ state->m_dvbt_rf_agc_cfg.output_level = 0;
+ state->m_dvbt_rf_agc_cfg.min_output_level = 0;
+ state->m_dvbt_rf_agc_cfg.max_output_level = 0xFFFF;
+ state->m_dvbt_rf_agc_cfg.top = 0x2100;
+ state->m_dvbt_rf_agc_cfg.cut_off_current = 4000;
+ state->m_dvbt_rf_agc_cfg.speed = 1;
/* DVBT IF */
- state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
- state->m_dvbtIfAgcCfg.outputLevel = 0;
- state->m_dvbtIfAgcCfg.minOutputLevel = 0;
- state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
- state->m_dvbtIfAgcCfg.top = 13424;
- state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
- state->m_dvbtIfAgcCfg.speed = 3;
- state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
- state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
+ state->m_dvbt_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
+ state->m_dvbt_if_agc_cfg.output_level = 0;
+ state->m_dvbt_if_agc_cfg.min_output_level = 0;
+ state->m_dvbt_if_agc_cfg.max_output_level = 9000;
+ state->m_dvbt_if_agc_cfg.top = 13424;
+ state->m_dvbt_if_agc_cfg.cut_off_current = 0;
+ state->m_dvbt_if_agc_cfg.speed = 3;
+ state->m_dvbt_if_agc_cfg.fast_clip_ctrl_delay = 30;
+ state->m_dvbt_if_agc_cfg.ingain_tgt_max = 30000;
/* state->m_dvbtPgaCfg = 140; */
- state->m_dvbtPreSawCfg.reference = 4;
- state->m_dvbtPreSawCfg.usePreSaw = false;
+ state->m_dvbt_pre_saw_cfg.reference = 4;
+ state->m_dvbt_pre_saw_cfg.use_pre_saw = false;
/* QAM RF */
- state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
- state->m_qamRfAgcCfg.outputLevel = 0;
- state->m_qamRfAgcCfg.minOutputLevel = 6023;
- state->m_qamRfAgcCfg.maxOutputLevel = 27000;
- state->m_qamRfAgcCfg.top = 0x2380;
- state->m_qamRfAgcCfg.cutOffCurrent = 4000;
- state->m_qamRfAgcCfg.speed = 3;
+ state->m_qam_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
+ state->m_qam_rf_agc_cfg.output_level = 0;
+ state->m_qam_rf_agc_cfg.min_output_level = 6023;
+ state->m_qam_rf_agc_cfg.max_output_level = 27000;
+ state->m_qam_rf_agc_cfg.top = 0x2380;
+ state->m_qam_rf_agc_cfg.cut_off_current = 4000;
+ state->m_qam_rf_agc_cfg.speed = 3;
/* QAM IF */
- state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
- state->m_qamIfAgcCfg.outputLevel = 0;
- state->m_qamIfAgcCfg.minOutputLevel = 0;
- state->m_qamIfAgcCfg.maxOutputLevel = 9000;
- state->m_qamIfAgcCfg.top = 0x0511;
- state->m_qamIfAgcCfg.cutOffCurrent = 0;
- state->m_qamIfAgcCfg.speed = 3;
- state->m_qamIfAgcCfg.IngainTgtMax = 5119;
- state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
-
- state->m_qamPgaCfg = 140;
- state->m_qamPreSawCfg.reference = 4;
- state->m_qamPreSawCfg.usePreSaw = false;
-
- state->m_OperationMode = OM_NONE;
- state->m_DrxkState = DRXK_UNINITIALIZED;
+ state->m_qam_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
+ state->m_qam_if_agc_cfg.output_level = 0;
+ state->m_qam_if_agc_cfg.min_output_level = 0;
+ state->m_qam_if_agc_cfg.max_output_level = 9000;
+ state->m_qam_if_agc_cfg.top = 0x0511;
+ state->m_qam_if_agc_cfg.cut_off_current = 0;
+ state->m_qam_if_agc_cfg.speed = 3;
+ state->m_qam_if_agc_cfg.ingain_tgt_max = 5119;
+ state->m_qam_if_agc_cfg.fast_clip_ctrl_delay = 50;
+
+ state->m_qam_pga_cfg = 140;
+ state->m_qam_pre_saw_cfg.reference = 4;
+ state->m_qam_pre_saw_cfg.use_pre_saw = false;
+
+ state->m_operation_mode = OM_NONE;
+ state->m_drxk_state = DRXK_UNINITIALIZED;
/* MPEG output configuration */
- state->m_enableMPEGOutput = true; /* If TRUE; enable MPEG ouput */
- state->m_insertRSByte = false; /* If TRUE; insert RS byte */
- state->m_invertDATA = false; /* If TRUE; invert DATA signals */
- state->m_invertERR = false; /* If TRUE; invert ERR signal */
- state->m_invertSTR = false; /* If TRUE; invert STR signals */
- state->m_invertVAL = false; /* If TRUE; invert VAL signals */
- state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */
+ state->m_enable_mpeg_output = true; /* If TRUE; enable MPEG ouput */
+ state->m_insert_rs_byte = false; /* If TRUE; insert RS byte */
+ state->m_invert_data = false; /* If TRUE; invert DATA signals */
+ state->m_invert_err = false; /* If TRUE; invert ERR signal */
+ state->m_invert_str = false; /* If TRUE; invert STR signals */
+ state->m_invert_val = false; /* If TRUE; invert VAL signals */
+ state->m_invert_clk = (ul_invert_ts_clock != 0); /* If TRUE; invert CLK signals */
/* If TRUE; static MPEG clockrate will be used;
otherwise clockrate will adapt to the bitrate of the TS */
- state->m_DVBTBitrate = ulDVBTBitrate;
- state->m_DVBCBitrate = ulDVBCBitrate;
+ state->m_dvbt_bitrate = ul_dvbt_bitrate;
+ state->m_dvbc_bitrate = ul_dvbc_bitrate;
- state->m_TSDataStrength = (ulTSDataStrength & 0x07);
+ state->m_ts_data_strength = (ul_ts_data_strength & 0x07);
/* Maximum bitrate in b/s in case static clockrate is selected */
- state->m_mpegTsStaticBitrate = 19392658;
- state->m_disableTEIhandling = false;
+ state->m_mpeg_ts_static_bitrate = 19392658;
+ state->m_disable_te_ihandling = false;
- if (ulInsertRSByte)
- state->m_insertRSByte = true;
+ if (ul_insert_rs_byte)
+ state->m_insert_rs_byte = true;
- state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
- if (ulMpegLockTimeOut < 10000)
- state->m_MpegLockTimeOut = ulMpegLockTimeOut;
- state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
- if (ulDemodLockTimeOut < 10000)
- state->m_DemodLockTimeOut = ulDemodLockTimeOut;
+ state->m_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+ if (ul_mpeg_lock_time_out < 10000)
+ state->m_mpeg_lock_time_out = ul_mpeg_lock_time_out;
+ state->m_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+ if (ul_demod_lock_time_out < 10000)
+ state->m_demod_lock_time_out = ul_demod_lock_time_out;
/* QAM defaults */
- state->m_Constellation = DRX_CONSTELLATION_AUTO;
- state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
- state->m_fecRsPlen = 204 * 8; /* fecRsPlen annex A */
- state->m_fecRsPrescale = 1;
+ state->m_constellation = DRX_CONSTELLATION_AUTO;
+ state->m_qam_interleave_mode = DRXK_QAM_I12_J17;
+ state->m_fec_rs_plen = 204 * 8; /* fecRsPlen annex A */
+ state->m_fec_rs_prescale = 1;
- state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
- state->m_agcFastClipCtrlDelay = 0;
+ state->m_sqi_speed = DRXK_DVBT_SQI_SPEED_MEDIUM;
+ state->m_agcfast_clip_ctrl_delay = 0;
- state->m_GPIOCfg = (ulGPIOCfg);
+ state->m_gpio_cfg = ul_gpio_cfg;
- state->m_bPowerDown = false;
- state->m_currentPowerMode = DRX_POWER_DOWN;
+ state->m_b_power_down = false;
+ state->m_current_power_mode = DRX_POWER_DOWN;
- state->m_rfmirror = (ulRfMirror == 0);
- state->m_IfAgcPol = false;
+ state->m_rfmirror = (ul_rf_mirror == 0);
+ state->m_if_agc_pol = false;
return 0;
}
-static int DRXX_Open(struct drxk_state *state)
+static int drxx_open(struct drxk_state *state)
{
int status = 0;
u32 jtag = 0;
@@ -869,7 +785,8 @@ static int DRXX_Open(struct drxk_state *state)
dprintk(1, "\n");
/* stop lock indicator process */
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
/* Check device id */
@@ -888,14 +805,14 @@ static int DRXX_Open(struct drxk_state *state)
status = write16(state, SIO_TOP_COMM_KEY__A, key);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int GetDeviceCapabilities(struct drxk_state *state)
+static int get_device_capabilities(struct drxk_state *state)
{
- u16 sioPdrOhwCfg = 0;
- u32 sioTopJtagidLo = 0;
+ u16 sio_pdr_ohw_cfg = 0;
+ u32 sio_top_jtagid_lo = 0;
int status;
const char *spin = "";
@@ -903,197 +820,196 @@ static int GetDeviceCapabilities(struct drxk_state *state)
/* driver 0.9.0 */
/* stop lock indicator process */
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
if (status < 0)
goto error;
- status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
+ status = read16(state, SIO_PDR_OHW_CFG__A, &sio_pdr_ohw_cfg);
if (status < 0)
goto error;
status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
if (status < 0)
goto error;
- switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+ switch ((sio_pdr_ohw_cfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
case 0:
/* ignore (bypass ?) */
break;
case 1:
/* 27 MHz */
- state->m_oscClockFreq = 27000;
+ state->m_osc_clock_freq = 27000;
break;
case 2:
/* 20.25 MHz */
- state->m_oscClockFreq = 20250;
+ state->m_osc_clock_freq = 20250;
break;
case 3:
/* 4 MHz */
- state->m_oscClockFreq = 20250;
+ state->m_osc_clock_freq = 20250;
break;
default:
- printk(KERN_ERR "drxk: Clock Frequency is unknown\n");
+ pr_err("Clock Frequency is unknown\n");
return -EINVAL;
}
/*
Determine device capabilities
Based on pinning v14
*/
- status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
+ status = read32(state, SIO_TOP_JTAGID_LO__A, &sio_top_jtagid_lo);
if (status < 0)
goto error;
- printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
+ pr_info("status = 0x%08x\n", sio_top_jtagid_lo);
/* driver 0.9.0 */
- switch ((sioTopJtagidLo >> 29) & 0xF) {
+ switch ((sio_top_jtagid_lo >> 29) & 0xF) {
case 0:
- state->m_deviceSpin = DRXK_SPIN_A1;
+ state->m_device_spin = DRXK_SPIN_A1;
spin = "A1";
break;
case 2:
- state->m_deviceSpin = DRXK_SPIN_A2;
+ state->m_device_spin = DRXK_SPIN_A2;
spin = "A2";
break;
case 3:
- state->m_deviceSpin = DRXK_SPIN_A3;
+ state->m_device_spin = DRXK_SPIN_A3;
spin = "A3";
break;
default:
- state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
+ state->m_device_spin = DRXK_SPIN_UNKNOWN;
status = -EINVAL;
- printk(KERN_ERR "drxk: Spin %d unknown\n",
- (sioTopJtagidLo >> 29) & 0xF);
+ pr_err("Spin %d unknown\n", (sio_top_jtagid_lo >> 29) & 0xF);
goto error2;
}
- switch ((sioTopJtagidLo >> 12) & 0xFF) {
+ switch ((sio_top_jtagid_lo >> 12) & 0xFF) {
case 0x13:
/* typeId = DRX3913K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = false;
- state->m_hasAudio = false;
- state->m_hasDVBT = true;
- state->m_hasDVBC = true;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = false;
- state->m_hasGPIO1 = false;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = false;
+ state->m_has_audio = false;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = true;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = false;
+ state->m_has_gpio1 = false;
+ state->m_has_irqn = false;
break;
case 0x15:
/* typeId = DRX3915K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = false;
- state->m_hasDVBT = true;
- state->m_hasDVBC = false;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = false;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = false;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x16:
/* typeId = DRX3916K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = false;
- state->m_hasDVBT = true;
- state->m_hasDVBC = false;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = false;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = false;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x18:
/* typeId = DRX3918K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = true;
- state->m_hasDVBT = true;
- state->m_hasDVBC = false;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = true;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = false;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x21:
/* typeId = DRX3921K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = true;
- state->m_hasDVBT = true;
- state->m_hasDVBC = true;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = true;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = true;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x23:
/* typeId = DRX3923K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = true;
- state->m_hasDVBT = true;
- state->m_hasDVBC = true;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = true;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = true;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x25:
/* typeId = DRX3925K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = true;
- state->m_hasDVBT = true;
- state->m_hasDVBC = true;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = true;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = true;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
case 0x26:
/* typeId = DRX3926K_TYPE_ID */
- state->m_hasLNA = false;
- state->m_hasOOB = false;
- state->m_hasATV = true;
- state->m_hasAudio = false;
- state->m_hasDVBT = true;
- state->m_hasDVBC = true;
- state->m_hasSAWSW = true;
- state->m_hasGPIO2 = true;
- state->m_hasGPIO1 = true;
- state->m_hasIRQN = false;
+ state->m_has_lna = false;
+ state->m_has_oob = false;
+ state->m_has_atv = true;
+ state->m_has_audio = false;
+ state->m_has_dvbt = true;
+ state->m_has_dvbc = true;
+ state->m_has_sawsw = true;
+ state->m_has_gpio2 = true;
+ state->m_has_gpio1 = true;
+ state->m_has_irqn = false;
break;
default:
- printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
- ((sioTopJtagidLo >> 12) & 0xFF));
+ pr_err("DeviceID 0x%02x not supported\n",
+ ((sio_top_jtagid_lo >> 12) & 0xFF));
status = -EINVAL;
goto error2;
}
- printk(KERN_INFO
- "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
- ((sioTopJtagidLo >> 12) & 0xFF), spin,
- state->m_oscClockFreq / 1000,
- state->m_oscClockFreq % 1000);
+ pr_info("detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
+ ((sio_top_jtagid_lo >> 12) & 0xFF), spin,
+ state->m_osc_clock_freq / 1000,
+ state->m_osc_clock_freq % 1000);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
error2:
return status;
}
-static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
+static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
{
int status;
bool powerdown_cmd;
@@ -1105,37 +1021,37 @@ static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
if (status < 0)
goto error;
if (cmd == SIO_HI_RA_RAM_CMD_RESET)
- msleep(1);
+ usleep_range(1000, 2000);
powerdown_cmd =
(bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
- ((state->m_HICfgCtrl) &
+ ((state->m_hi_cfg_ctrl) &
SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
if (powerdown_cmd == false) {
/* Wait until command rdy */
- u32 retryCount = 0;
- u16 waitCmd;
+ u32 retry_count = 0;
+ u16 wait_cmd;
do {
- msleep(1);
- retryCount += 1;
+ usleep_range(1000, 2000);
+ retry_count += 1;
status = read16(state, SIO_HI_RA_RAM_CMD__A,
- &waitCmd);
- } while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
- && (waitCmd != 0));
+ &wait_cmd);
+ } while ((status < 0) && (retry_count < DRXK_MAX_RETRIES)
+ && (wait_cmd != 0));
if (status < 0)
goto error;
- status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
+ status = read16(state, SIO_HI_RA_RAM_RES__A, p_result);
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int HI_CfgCommand(struct drxk_state *state)
+static int hi_cfg_command(struct drxk_state *state)
{
int status;
@@ -1143,61 +1059,68 @@ static int HI_CfgCommand(struct drxk_state *state)
mutex_lock(&state->mutex);
- status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
+ status = write16(state, SIO_HI_RA_RAM_PAR_6__A,
+ state->m_hi_cfg_timeout);
if (status < 0)
goto error;
- status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
+ status = write16(state, SIO_HI_RA_RAM_PAR_5__A,
+ state->m_hi_cfg_ctrl);
if (status < 0)
goto error;
- status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
+ status = write16(state, SIO_HI_RA_RAM_PAR_4__A,
+ state->m_hi_cfg_wake_up_key);
if (status < 0)
goto error;
- status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
+ status = write16(state, SIO_HI_RA_RAM_PAR_3__A,
+ state->m_hi_cfg_bridge_delay);
if (status < 0)
goto error;
- status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
+ status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+ state->m_hi_cfg_timing_div);
if (status < 0)
goto error;
- status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+ status = write16(state, SIO_HI_RA_RAM_PAR_1__A,
+ SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
if (status < 0)
goto error;
- status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+ status = hi_command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
if (status < 0)
goto error;
- state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+ state->m_hi_cfg_ctrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
error:
mutex_unlock(&state->mutex);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int InitHI(struct drxk_state *state)
+static int init_hi(struct drxk_state *state)
{
dprintk(1, "\n");
- state->m_HICfgWakeUpKey = (state->demod_address << 1);
- state->m_HICfgTimeout = 0x96FF;
+ state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
+ state->m_hi_cfg_timeout = 0x96FF;
/* port/bridge/power down ctrl */
- state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+ state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
- return HI_CfgCommand(state);
+ return hi_cfg_command(state);
}
-static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
+static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
{
int status = -1;
- u16 sioPdrMclkCfg = 0;
- u16 sioPdrMdxCfg = 0;
+ u16 sio_pdr_mclk_cfg = 0;
+ u16 sio_pdr_mdx_cfg = 0;
u16 err_cfg = 0;
dprintk(1, ": mpeg %s, %s mode\n",
- mpegEnable ? "enable" : "disable",
- state->m_enableParallel ? "parallel" : "serial");
+ mpeg_enable ? "enable" : "disable",
+ state->m_enable_parallel ? "parallel" : "serial");
/* stop lock indicator process */
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
@@ -1206,7 +1129,7 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
if (status < 0)
goto error;
- if (mpegEnable == false) {
+ if (mpeg_enable == false) {
/* Set MPEG TS pads to inputmode */
status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
if (status < 0)
@@ -1246,19 +1169,19 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
goto error;
} else {
/* Enable MPEG output */
- sioPdrMdxCfg =
- ((state->m_TSDataStrength <<
+ sio_pdr_mdx_cfg =
+ ((state->m_ts_data_strength <<
SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
- sioPdrMclkCfg = ((state->m_TSClockkStrength <<
+ sio_pdr_mclk_cfg = ((state->m_ts_clockk_strength <<
SIO_PDR_MCLK_CFG_DRIVE__B) |
0x0003);
- status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MSTRT_CFG__A, sio_pdr_mdx_cfg);
if (status < 0)
goto error;
if (state->enable_merr_cfg)
- err_cfg = sioPdrMdxCfg;
+ err_cfg = sio_pdr_mdx_cfg;
status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
if (status < 0)
@@ -1267,31 +1190,38 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
if (status < 0)
goto error;
- if (state->m_enableParallel == true) {
+ if (state->m_enable_parallel == true) {
/* paralel -> enable MD1 to MD7 */
- status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD1_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD2_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD3_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD4_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD5_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD6_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD7_CFG__A,
+ sio_pdr_mdx_cfg);
if (status < 0)
goto error;
} else {
- sioPdrMdxCfg = ((state->m_TSDataStrength <<
+ sio_pdr_mdx_cfg = ((state->m_ts_data_strength <<
SIO_PDR_MD0_CFG_DRIVE__B)
| 0x0003);
/* serial -> disable MD1 to MD7 */
@@ -1317,10 +1247,10 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
if (status < 0)
goto error;
}
- status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
+ status = write16(state, SIO_PDR_MCLK_CFG__A, sio_pdr_mclk_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
+ status = write16(state, SIO_PDR_MD0_CFG__A, sio_pdr_mdx_cfg);
if (status < 0)
goto error;
}
@@ -1332,21 +1262,21 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int MPEGTSDisable(struct drxk_state *state)
+static int mpegts_disable(struct drxk_state *state)
{
dprintk(1, "\n");
- return MPEGTSConfigurePins(state, false);
+ return mpegts_configure_pins(state, false);
}
-static int BLChainCmd(struct drxk_state *state,
- u16 romOffset, u16 nrOfElements, u32 timeOut)
+static int bl_chain_cmd(struct drxk_state *state,
+ u16 rom_offset, u16 nr_of_elements, u32 time_out)
{
- u16 blStatus = 0;
+ u16 bl_status = 0;
int status;
unsigned long end;
@@ -1355,46 +1285,46 @@ static int BLChainCmd(struct drxk_state *state,
status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
if (status < 0)
goto error;
- status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
+ status = write16(state, SIO_BL_CHAIN_ADDR__A, rom_offset);
if (status < 0)
goto error;
- status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
+ status = write16(state, SIO_BL_CHAIN_LEN__A, nr_of_elements);
if (status < 0)
goto error;
status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
if (status < 0)
goto error;
- end = jiffies + msecs_to_jiffies(timeOut);
+ end = jiffies + msecs_to_jiffies(time_out);
do {
- msleep(1);
- status = read16(state, SIO_BL_STATUS__A, &blStatus);
+ usleep_range(1000, 2000);
+ status = read16(state, SIO_BL_STATUS__A, &bl_status);
if (status < 0)
goto error;
- } while ((blStatus == 0x1) &&
+ } while ((bl_status == 0x1) &&
((time_is_after_jiffies(end))));
- if (blStatus == 0x1) {
- printk(KERN_ERR "drxk: SIO not ready\n");
+ if (bl_status == 0x1) {
+ pr_err("SIO not ready\n");
status = -EINVAL;
goto error2;
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
error2:
mutex_unlock(&state->mutex);
return status;
}
-static int DownloadMicrocode(struct drxk_state *state,
- const u8 pMCImage[], u32 Length)
+static int download_microcode(struct drxk_state *state,
+ const u8 p_mc_image[], u32 length)
{
- const u8 *pSrc = pMCImage;
- u32 Address;
- u16 nBlocks;
- u16 BlockSize;
+ const u8 *p_src = p_mc_image;
+ u32 address;
+ u16 n_blocks;
+ u16 block_size;
u32 offset = 0;
u32 i;
int status = 0;
@@ -1404,130 +1334,131 @@ static int DownloadMicrocode(struct drxk_state *state,
/* down the drain (we don't care about MAGIC_WORD) */
#if 0
/* For future reference */
- Drain = (pSrc[0] << 8) | pSrc[1];
+ drain = (p_src[0] << 8) | p_src[1];
#endif
- pSrc += sizeof(u16);
+ p_src += sizeof(u16);
offset += sizeof(u16);
- nBlocks = (pSrc[0] << 8) | pSrc[1];
- pSrc += sizeof(u16);
+ n_blocks = (p_src[0] << 8) | p_src[1];
+ p_src += sizeof(u16);
offset += sizeof(u16);
- for (i = 0; i < nBlocks; i += 1) {
- Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
- (pSrc[2] << 8) | pSrc[3];
- pSrc += sizeof(u32);
+ for (i = 0; i < n_blocks; i += 1) {
+ address = (p_src[0] << 24) | (p_src[1] << 16) |
+ (p_src[2] << 8) | p_src[3];
+ p_src += sizeof(u32);
offset += sizeof(u32);
- BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
- pSrc += sizeof(u16);
+ block_size = ((p_src[0] << 8) | p_src[1]) * sizeof(u16);
+ p_src += sizeof(u16);
offset += sizeof(u16);
#if 0
/* For future reference */
- Flags = (pSrc[0] << 8) | pSrc[1];
+ flags = (p_src[0] << 8) | p_src[1];
#endif
- pSrc += sizeof(u16);
+ p_src += sizeof(u16);
offset += sizeof(u16);
#if 0
/* For future reference */
- BlockCRC = (pSrc[0] << 8) | pSrc[1];
+ block_crc = (p_src[0] << 8) | p_src[1];
#endif
- pSrc += sizeof(u16);
+ p_src += sizeof(u16);
offset += sizeof(u16);
- if (offset + BlockSize > Length) {
- printk(KERN_ERR "drxk: Firmware is corrupted.\n");
+ if (offset + block_size > length) {
+ pr_err("Firmware is corrupted.\n");
return -EINVAL;
}
- status = write_block(state, Address, BlockSize, pSrc);
+ status = write_block(state, address, block_size, p_src);
if (status < 0) {
- printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
+ pr_err("Error %d while loading firmware\n", status);
break;
}
- pSrc += BlockSize;
- offset += BlockSize;
+ p_src += block_size;
+ offset += block_size;
}
return status;
}
-static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
+static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable)
{
int status;
u16 data = 0;
- u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
- u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
+ u16 desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
+ u16 desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
unsigned long end;
dprintk(1, "\n");
if (enable == false) {
- desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
- desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
+ desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
+ desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
}
status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
- if (status >= 0 && data == desiredStatus) {
+ if (status >= 0 && data == desired_status) {
/* tokenring already has correct status */
return status;
}
/* Disable/enable dvbt tokenring bridge */
- status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
+ status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desired_ctrl);
end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
do {
status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
- if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
+ if ((status >= 0 && data == desired_status)
+ || time_is_after_jiffies(end))
break;
- msleep(1);
+ usleep_range(1000, 2000);
} while (1);
- if (data != desiredStatus) {
- printk(KERN_ERR "drxk: SIO not ready\n");
+ if (data != desired_status) {
+ pr_err("SIO not ready\n");
return -EINVAL;
}
return status;
}
-static int MPEGTSStop(struct drxk_state *state)
+static int mpegts_stop(struct drxk_state *state)
{
int status = 0;
- u16 fecOcSncMode = 0;
- u16 fecOcIprMode = 0;
+ u16 fec_oc_snc_mode = 0;
+ u16 fec_oc_ipr_mode = 0;
dprintk(1, "\n");
/* Gracefull shutdown (byte boundaries) */
- status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+ status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
if (status < 0)
goto error;
- fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
- status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+ fec_oc_snc_mode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
+ status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
if (status < 0)
goto error;
/* Suppress MCLK during absence of data */
- status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
+ status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_ipr_mode);
if (status < 0)
goto error;
- fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
- status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
+ fec_oc_ipr_mode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
+ status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_ipr_mode);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
static int scu_command(struct drxk_state *state,
- u16 cmd, u8 parameterLen,
- u16 *parameter, u8 resultLen, u16 *result)
+ u16 cmd, u8 parameter_len,
+ u16 *parameter, u8 result_len, u16 *result)
{
#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
#error DRXK register mapping no longer compatible with this routine!
#endif
- u16 curCmd = 0;
+ u16 cur_cmd = 0;
int status = -EINVAL;
unsigned long end;
u8 buffer[34];
@@ -1537,9 +1468,9 @@ static int scu_command(struct drxk_state *state,
dprintk(1, "\n");
- if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
- ((resultLen > 0) && (result == NULL))) {
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ if ((cmd == 0) || ((parameter_len > 0) && (parameter == NULL)) ||
+ ((result_len > 0) && (result == NULL))) {
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -1547,7 +1478,7 @@ static int scu_command(struct drxk_state *state,
/* assume that the command register is ready
since it is checked afterwards */
- for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
+ for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
buffer[cnt++] = (parameter[ii] & 0xFF);
buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
}
@@ -1555,27 +1486,28 @@ static int scu_command(struct drxk_state *state,
buffer[cnt++] = ((cmd >> 8) & 0xFF);
write_block(state, SCU_RAM_PARAM_0__A -
- (parameterLen - 1), cnt, buffer);
+ (parameter_len - 1), cnt, buffer);
/* Wait until SCU has processed command */
end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
do {
- msleep(1);
- status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
+ usleep_range(1000, 2000);
+ status = read16(state, SCU_RAM_COMMAND__A, &cur_cmd);
if (status < 0)
goto error;
- } while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
- if (curCmd != DRX_SCU_READY) {
- printk(KERN_ERR "drxk: SCU not ready\n");
+ } while (!(cur_cmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
+ if (cur_cmd != DRX_SCU_READY) {
+ pr_err("SCU not ready\n");
status = -EIO;
goto error2;
}
/* read results */
- if ((resultLen > 0) && (result != NULL)) {
+ if ((result_len > 0) && (result != NULL)) {
s16 err;
int ii;
- for (ii = resultLen - 1; ii >= 0; ii -= 1) {
- status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
+ for (ii = result_len - 1; ii >= 0; ii -= 1) {
+ status = read16(state, SCU_RAM_PARAM_0__A - ii,
+ &result[ii]);
if (status < 0)
goto error;
}
@@ -1603,7 +1535,7 @@ static int scu_command(struct drxk_state *state,
sprintf(errname, "ERROR: %d\n", err);
p = errname;
}
- printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
+ pr_err("%s while sending cmd 0x%04x with params:", p, cmd);
print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
status = -EINVAL;
goto error2;
@@ -1611,13 +1543,13 @@ static int scu_command(struct drxk_state *state,
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
error2:
mutex_unlock(&state->mutex);
return status;
}
-static int SetIqmAf(struct drxk_state *state, bool active)
+static int set_iqm_af(struct drxk_state *state, bool active)
{
u16 data = 0;
int status;
@@ -1647,14 +1579,14 @@ static int SetIqmAf(struct drxk_state *state, bool active)
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
+static int ctrl_power_mode(struct drxk_state *state, enum drx_power_mode *mode)
{
int status = 0;
- u16 sioCcPwdMode = 0;
+ u16 sio_cc_pwd_mode = 0;
dprintk(1, "\n");
@@ -1664,19 +1596,19 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
switch (*mode) {
case DRX_POWER_UP:
- sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE;
break;
case DRXK_POWER_DOWN_OFDM:
- sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OFDM;
break;
case DRXK_POWER_DOWN_CORE:
- sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
break;
case DRXK_POWER_DOWN_PLL:
- sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL;
break;
case DRX_POWER_DOWN:
- sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
break;
default:
/* Unknow sleep mode */
@@ -1684,15 +1616,15 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
}
/* If already in requested power mode, do nothing */
- if (state->m_currentPowerMode == *mode)
+ if (state->m_current_power_mode == *mode)
return 0;
/* For next steps make sure to start from DRX_POWER_UP mode */
- if (state->m_currentPowerMode != DRX_POWER_UP) {
- status = PowerUpDevice(state);
+ if (state->m_current_power_mode != DRX_POWER_UP) {
+ status = power_up_device(state);
if (status < 0)
goto error;
- status = DVBTEnableOFDMTokenRing(state, true);
+ status = dvbt_enable_ofdm_token_ring(state, true);
if (status < 0)
goto error;
}
@@ -1709,31 +1641,31 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
/* Power down device */
/* stop all comm_exec */
/* Stop and power down previous standard */
- switch (state->m_OperationMode) {
+ switch (state->m_operation_mode) {
case OM_DVBT:
- status = MPEGTSStop(state);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = PowerDownDVBT(state, false);
+ status = power_down_dvbt(state, false);
if (status < 0)
goto error;
break;
case OM_QAM_ITU_A:
case OM_QAM_ITU_C:
- status = MPEGTSStop(state);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = PowerDownQAM(state);
+ status = power_down_qam(state);
if (status < 0)
goto error;
break;
default:
break;
}
- status = DVBTEnableOFDMTokenRing(state, false);
+ status = dvbt_enable_ofdm_token_ring(state, false);
if (status < 0)
goto error;
- status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
+ status = write16(state, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode);
if (status < 0)
goto error;
status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
@@ -1741,26 +1673,26 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
goto error;
if (*mode != DRXK_POWER_DOWN_OFDM) {
- state->m_HICfgCtrl |=
+ state->m_hi_cfg_ctrl |=
SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
- status = HI_CfgCommand(state);
+ status = hi_cfg_command(state);
if (status < 0)
goto error;
}
}
- state->m_currentPowerMode = *mode;
+ state->m_current_power_mode = *mode;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
+static int power_down_dvbt(struct drxk_state *state, bool set_power_mode)
{
- enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
- u16 cmdResult = 0;
+ enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
+ u16 cmd_result = 0;
u16 data = 0;
int status;
@@ -1771,11 +1703,17 @@ static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
goto error;
if (data == SCU_COMM_EXEC_ACTIVE) {
/* Send OFDM stop command */
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+ status = scu_command(state,
+ SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
/* Send OFDM reset command */
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+ status = scu_command(state,
+ SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
}
@@ -1792,24 +1730,24 @@ static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
goto error;
/* powerdown AFE */
- status = SetIqmAf(state, false);
+ status = set_iqm_af(state, false);
if (status < 0)
goto error;
/* powerdown to OFDM mode */
- if (setPowerMode) {
- status = CtrlPowerMode(state, &powerMode);
+ if (set_power_mode) {
+ status = ctrl_power_mode(state, &power_mode);
if (status < 0)
goto error;
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SetOperationMode(struct drxk_state *state,
- enum OperationMode oMode)
+static int setoperation_mode(struct drxk_state *state,
+ enum operation_mode o_mode)
{
int status = 0;
@@ -1821,36 +1759,37 @@ static int SetOperationMode(struct drxk_state *state,
*/
/* disable HW lock indicator */
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
/* Device is already at the required mode */
- if (state->m_OperationMode == oMode)
+ if (state->m_operation_mode == o_mode)
return 0;
- switch (state->m_OperationMode) {
+ switch (state->m_operation_mode) {
/* OM_NONE was added for start up */
case OM_NONE:
break;
case OM_DVBT:
- status = MPEGTSStop(state);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = PowerDownDVBT(state, true);
+ status = power_down_dvbt(state, true);
if (status < 0)
goto error;
- state->m_OperationMode = OM_NONE;
+ state->m_operation_mode = OM_NONE;
break;
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
- status = MPEGTSStop(state);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = PowerDownQAM(state);
+ status = power_down_qam(state);
if (status < 0)
goto error;
- state->m_OperationMode = OM_NONE;
+ state->m_operation_mode = OM_NONE;
break;
case OM_QAM_ITU_B:
default:
@@ -1861,20 +1800,20 @@ static int SetOperationMode(struct drxk_state *state,
/*
Power up new standard
*/
- switch (oMode) {
+ switch (o_mode) {
case OM_DVBT:
dprintk(1, ": DVB-T\n");
- state->m_OperationMode = oMode;
- status = SetDVBTStandard(state, oMode);
+ state->m_operation_mode = o_mode;
+ status = set_dvbt_standard(state, o_mode);
if (status < 0)
goto error;
break;
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
dprintk(1, ": DVB-C Annex %c\n",
- (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
- state->m_OperationMode = oMode;
- status = SetQAMStandard(state, oMode);
+ (state->m_operation_mode == OM_QAM_ITU_A) ? 'A' : 'C');
+ state->m_operation_mode = o_mode;
+ status = set_qam_standard(state, o_mode);
if (status < 0)
goto error;
break;
@@ -1884,121 +1823,121 @@ static int SetOperationMode(struct drxk_state *state,
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int Start(struct drxk_state *state, s32 offsetFreq,
- s32 IntermediateFrequency)
+static int start(struct drxk_state *state, s32 offset_freq,
+ s32 intermediate_frequency)
{
int status = -EINVAL;
- u16 IFreqkHz;
- s32 OffsetkHz = offsetFreq / 1000;
+ u16 i_freqk_hz;
+ s32 offsetk_hz = offset_freq / 1000;
dprintk(1, "\n");
- if (state->m_DrxkState != DRXK_STOPPED &&
- state->m_DrxkState != DRXK_DTV_STARTED)
+ if (state->m_drxk_state != DRXK_STOPPED &&
+ state->m_drxk_state != DRXK_DTV_STARTED)
goto error;
- state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
+ state->m_b_mirror_freq_spect = (state->props.inversion == INVERSION_ON);
- if (IntermediateFrequency < 0) {
- state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
- IntermediateFrequency = -IntermediateFrequency;
+ if (intermediate_frequency < 0) {
+ state->m_b_mirror_freq_spect = !state->m_b_mirror_freq_spect;
+ intermediate_frequency = -intermediate_frequency;
}
- switch (state->m_OperationMode) {
+ switch (state->m_operation_mode) {
case OM_QAM_ITU_A:
case OM_QAM_ITU_C:
- IFreqkHz = (IntermediateFrequency / 1000);
- status = SetQAM(state, IFreqkHz, OffsetkHz);
+ i_freqk_hz = (intermediate_frequency / 1000);
+ status = set_qam(state, i_freqk_hz, offsetk_hz);
if (status < 0)
goto error;
- state->m_DrxkState = DRXK_DTV_STARTED;
+ state->m_drxk_state = DRXK_DTV_STARTED;
break;
case OM_DVBT:
- IFreqkHz = (IntermediateFrequency / 1000);
- status = MPEGTSStop(state);
+ i_freqk_hz = (intermediate_frequency / 1000);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = SetDVBT(state, IFreqkHz, OffsetkHz);
+ status = set_dvbt(state, i_freqk_hz, offsetk_hz);
if (status < 0)
goto error;
- status = DVBTStart(state);
+ status = dvbt_start(state);
if (status < 0)
goto error;
- state->m_DrxkState = DRXK_DTV_STARTED;
+ state->m_drxk_state = DRXK_DTV_STARTED;
break;
default:
break;
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int ShutDown(struct drxk_state *state)
+static int shut_down(struct drxk_state *state)
{
dprintk(1, "\n");
- MPEGTSStop(state);
+ mpegts_stop(state);
return 0;
}
-static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_lock_status(struct drxk_state *state, u32 *p_lock_status)
{
int status = -EINVAL;
dprintk(1, "\n");
- if (pLockStatus == NULL)
+ if (p_lock_status == NULL)
goto error;
- *pLockStatus = NOT_LOCKED;
+ *p_lock_status = NOT_LOCKED;
/* define the SCU command code */
- switch (state->m_OperationMode) {
+ switch (state->m_operation_mode) {
case OM_QAM_ITU_A:
case OM_QAM_ITU_B:
case OM_QAM_ITU_C:
- status = GetQAMLockStatus(state, pLockStatus);
+ status = get_qam_lock_status(state, p_lock_status);
break;
case OM_DVBT:
- status = GetDVBTLockStatus(state, pLockStatus);
+ status = get_dvbt_lock_status(state, p_lock_status);
break;
default:
break;
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int MPEGTSStart(struct drxk_state *state)
+static int mpegts_start(struct drxk_state *state)
{
int status;
- u16 fecOcSncMode = 0;
+ u16 fec_oc_snc_mode = 0;
/* Allow OC to sync again */
- status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+ status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
if (status < 0)
goto error;
- fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
- status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+ fec_oc_snc_mode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
+ status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
if (status < 0)
goto error;
status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int MPEGTSDtoInit(struct drxk_state *state)
+static int mpegts_dto_init(struct drxk_state *state)
{
int status;
@@ -2040,68 +1979,68 @@ static int MPEGTSDtoInit(struct drxk_state *state)
status = write16(state, FEC_OC_SNC_HWM__A, 12);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int MPEGTSDtoSetup(struct drxk_state *state,
- enum OperationMode oMode)
+static int mpegts_dto_setup(struct drxk_state *state,
+ enum operation_mode o_mode)
{
int status;
- u16 fecOcRegMode = 0; /* FEC_OC_MODE register value */
- u16 fecOcRegIprMode = 0; /* FEC_OC_IPR_MODE register value */
- u16 fecOcDtoMode = 0; /* FEC_OC_IPR_INVERT register value */
- u16 fecOcFctMode = 0; /* FEC_OC_IPR_INVERT register value */
- u16 fecOcDtoPeriod = 2; /* FEC_OC_IPR_INVERT register value */
- u16 fecOcDtoBurstLen = 188; /* FEC_OC_IPR_INVERT register value */
- u32 fecOcRcnCtlRate = 0; /* FEC_OC_IPR_INVERT register value */
- u16 fecOcTmdMode = 0;
- u16 fecOcTmdIntUpdRate = 0;
- u32 maxBitRate = 0;
- bool staticCLK = false;
+ u16 fec_oc_reg_mode = 0; /* FEC_OC_MODE register value */
+ u16 fec_oc_reg_ipr_mode = 0; /* FEC_OC_IPR_MODE register value */
+ u16 fec_oc_dto_mode = 0; /* FEC_OC_IPR_INVERT register value */
+ u16 fec_oc_fct_mode = 0; /* FEC_OC_IPR_INVERT register value */
+ u16 fec_oc_dto_period = 2; /* FEC_OC_IPR_INVERT register value */
+ u16 fec_oc_dto_burst_len = 188; /* FEC_OC_IPR_INVERT register value */
+ u32 fec_oc_rcn_ctl_rate = 0; /* FEC_OC_IPR_INVERT register value */
+ u16 fec_oc_tmd_mode = 0;
+ u16 fec_oc_tmd_int_upd_rate = 0;
+ u32 max_bit_rate = 0;
+ bool static_clk = false;
dprintk(1, "\n");
/* Check insertion of the Reed-Solomon parity bytes */
- status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
+ status = read16(state, FEC_OC_MODE__A, &fec_oc_reg_mode);
if (status < 0)
goto error;
- status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
+ status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_reg_ipr_mode);
if (status < 0)
goto error;
- fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
- fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
- if (state->m_insertRSByte == true) {
+ fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
+ fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+ if (state->m_insert_rs_byte == true) {
/* enable parity symbol forward */
- fecOcRegMode |= FEC_OC_MODE_PARITY__M;
+ fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
/* MVAL disable during parity bytes */
- fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
/* TS burst length to 204 */
- fecOcDtoBurstLen = 204;
+ fec_oc_dto_burst_len = 204;
}
/* Check serial or parrallel output */
- fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
- if (state->m_enableParallel == false) {
+ fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+ if (state->m_enable_parallel == false) {
/* MPEG data output is serial -> set ipr_mode[0] */
- fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
+ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
}
- switch (oMode) {
+ switch (o_mode) {
case OM_DVBT:
- maxBitRate = state->m_DVBTBitrate;
- fecOcTmdMode = 3;
- fecOcRcnCtlRate = 0xC00000;
- staticCLK = state->m_DVBTStaticCLK;
+ max_bit_rate = state->m_dvbt_bitrate;
+ fec_oc_tmd_mode = 3;
+ fec_oc_rcn_ctl_rate = 0xC00000;
+ static_clk = state->m_dvbt_static_clk;
break;
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
- fecOcTmdMode = 0x0004;
- fecOcRcnCtlRate = 0xD2B4EE; /* good for >63 Mb/s */
- maxBitRate = state->m_DVBCBitrate;
- staticCLK = state->m_DVBCStaticCLK;
+ fec_oc_tmd_mode = 0x0004;
+ fec_oc_rcn_ctl_rate = 0xD2B4EE; /* good for >63 Mb/s */
+ max_bit_rate = state->m_dvbc_bitrate;
+ static_clk = state->m_dvbc_static_clk;
break;
default:
status = -EINVAL;
@@ -2110,83 +2049,84 @@ static int MPEGTSDtoSetup(struct drxk_state *state,
goto error;
/* Configure DTO's */
- if (staticCLK) {
- u32 bitRate = 0;
+ if (static_clk) {
+ u32 bit_rate = 0;
/* Rational DTO for MCLK source (static MCLK rate),
Dynamic DTO for optimal grouping
(avoid intra-packet gaps),
DTO offset enable to sync TS burst with MSTRT */
- fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
+ fec_oc_dto_mode = (FEC_OC_DTO_MODE_DYNAMIC__M |
FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
- fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
+ fec_oc_fct_mode = (FEC_OC_FCT_MODE_RAT_ENA__M |
FEC_OC_FCT_MODE_VIRT_ENA__M);
/* Check user defined bitrate */
- bitRate = maxBitRate;
- if (bitRate > 75900000UL) { /* max is 75.9 Mb/s */
- bitRate = 75900000UL;
+ bit_rate = max_bit_rate;
+ if (bit_rate > 75900000UL) { /* max is 75.9 Mb/s */
+ bit_rate = 75900000UL;
}
/* Rational DTO period:
dto_period = (Fsys / bitrate) - 2
- Result should be floored,
+ result should be floored,
to make sure >= requested bitrate
*/
- fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
- * 1000) / bitRate);
- if (fecOcDtoPeriod <= 2)
- fecOcDtoPeriod = 0;
+ fec_oc_dto_period = (u16) (((state->m_sys_clock_freq)
+ * 1000) / bit_rate);
+ if (fec_oc_dto_period <= 2)
+ fec_oc_dto_period = 0;
else
- fecOcDtoPeriod -= 2;
- fecOcTmdIntUpdRate = 8;
+ fec_oc_dto_period -= 2;
+ fec_oc_tmd_int_upd_rate = 8;
} else {
- /* (commonAttr->staticCLK == false) => dynamic mode */
- fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
- fecOcFctMode = FEC_OC_FCT_MODE__PRE;
- fecOcTmdIntUpdRate = 5;
+ /* (commonAttr->static_clk == false) => dynamic mode */
+ fec_oc_dto_mode = FEC_OC_DTO_MODE_DYNAMIC__M;
+ fec_oc_fct_mode = FEC_OC_FCT_MODE__PRE;
+ fec_oc_tmd_int_upd_rate = 5;
}
/* Write appropriate registers with requested configuration */
- status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
+ status = write16(state, FEC_OC_DTO_BURST_LEN__A, fec_oc_dto_burst_len);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
+ status = write16(state, FEC_OC_DTO_PERIOD__A, fec_oc_dto_period);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
+ status = write16(state, FEC_OC_DTO_MODE__A, fec_oc_dto_mode);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
+ status = write16(state, FEC_OC_FCT_MODE__A, fec_oc_fct_mode);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
+ status = write16(state, FEC_OC_MODE__A, fec_oc_reg_mode);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
+ status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_reg_ipr_mode);
if (status < 0)
goto error;
/* Rate integration settings */
- status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
+ status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fec_oc_rcn_ctl_rate);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
+ status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A,
+ fec_oc_tmd_int_upd_rate);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
+ status = write16(state, FEC_OC_TMD_MODE__A, fec_oc_tmd_mode);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int MPEGTSConfigurePolarity(struct drxk_state *state)
+static int mpegts_configure_polarity(struct drxk_state *state)
{
- u16 fecOcRegIprInvert = 0;
+ u16 fec_oc_reg_ipr_invert = 0;
/* Data mask for the output data byte */
- u16 InvertDataMask =
+ u16 invert_data_mask =
FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
@@ -2195,40 +2135,40 @@ static int MPEGTSConfigurePolarity(struct drxk_state *state)
dprintk(1, "\n");
/* Control selective inversion of output bits */
- fecOcRegIprInvert &= (~(InvertDataMask));
- if (state->m_invertDATA == true)
- fecOcRegIprInvert |= InvertDataMask;
- fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
- if (state->m_invertERR == true)
- fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
- fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
- if (state->m_invertSTR == true)
- fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
- fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
- if (state->m_invertVAL == true)
- fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
- fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
- if (state->m_invertCLK == true)
- fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
-
- return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
+ fec_oc_reg_ipr_invert &= (~(invert_data_mask));
+ if (state->m_invert_data == true)
+ fec_oc_reg_ipr_invert |= invert_data_mask;
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+ if (state->m_invert_err == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+ if (state->m_invert_str == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+ if (state->m_invert_val == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+ if (state->m_invert_clk == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
+
+ return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
}
#define SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
-static int SetAgcRf(struct drxk_state *state,
- struct SCfgAgc *pAgcCfg, bool isDTV)
+static int set_agc_rf(struct drxk_state *state,
+ struct s_cfg_agc *p_agc_cfg, bool is_dtv)
{
int status = -EINVAL;
u16 data = 0;
- struct SCfgAgc *pIfAgcSettings;
+ struct s_cfg_agc *p_if_agc_settings;
dprintk(1, "\n");
- if (pAgcCfg == NULL)
+ if (p_agc_cfg == NULL)
goto error;
- switch (pAgcCfg->ctrlMode) {
+ switch (p_agc_cfg->ctrl_mode) {
case DRXK_AGC_CTRL_AUTO:
/* Enable RF AGC DAC */
status = read16(state, IQM_AF_STDBY__A, &data);
@@ -2246,7 +2186,7 @@ static int SetAgcRf(struct drxk_state *state,
data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
/* Polarity */
- if (state->m_RfAgcPol)
+ if (state->m_rf_agc_pol)
data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
else
data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
@@ -2260,7 +2200,7 @@ static int SetAgcRf(struct drxk_state *state,
goto error;
data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
- data |= (~(pAgcCfg->speed <<
+ data |= (~(p_agc_cfg->speed <<
SCU_RAM_AGC_KI_RED_RAGC_RED__B)
& SCU_RAM_AGC_KI_RED_RAGC_RED__M);
@@ -2268,30 +2208,34 @@ static int SetAgcRf(struct drxk_state *state,
if (status < 0)
goto error;
- if (IsDVBT(state))
- pIfAgcSettings = &state->m_dvbtIfAgcCfg;
- else if (IsQAM(state))
- pIfAgcSettings = &state->m_qamIfAgcCfg;
+ if (is_dvbt(state))
+ p_if_agc_settings = &state->m_dvbt_if_agc_cfg;
+ else if (is_qam(state))
+ p_if_agc_settings = &state->m_qam_if_agc_cfg;
else
- pIfAgcSettings = &state->m_atvIfAgcCfg;
- if (pIfAgcSettings == NULL) {
+ p_if_agc_settings = &state->m_atv_if_agc_cfg;
+ if (p_if_agc_settings == NULL) {
status = -EINVAL;
goto error;
}
/* Set TOP, only if IF-AGC is in AUTO mode */
- if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
+ if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO)
+ status = write16(state,
+ SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+ p_agc_cfg->top);
if (status < 0)
goto error;
/* Cut-Off current */
- status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
+ status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
+ p_agc_cfg->cut_off_current);
if (status < 0)
goto error;
/* Max. output level */
- status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
+ status = write16(state, SCU_RAM_AGC_RF_MAX__A,
+ p_agc_cfg->max_output_level);
if (status < 0)
goto error;
@@ -2312,7 +2256,7 @@ static int SetAgcRf(struct drxk_state *state,
if (status < 0)
goto error;
data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
- if (state->m_RfAgcPol)
+ if (state->m_rf_agc_pol)
data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
else
data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
@@ -2326,7 +2270,8 @@ static int SetAgcRf(struct drxk_state *state,
goto error;
/* Write value to output pin */
- status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
+ status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A,
+ p_agc_cfg->output_level);
if (status < 0)
goto error;
break;
@@ -2357,22 +2302,22 @@ static int SetAgcRf(struct drxk_state *state,
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
-static int SetAgcIf(struct drxk_state *state,
- struct SCfgAgc *pAgcCfg, bool isDTV)
+static int set_agc_if(struct drxk_state *state,
+ struct s_cfg_agc *p_agc_cfg, bool is_dtv)
{
u16 data = 0;
int status = 0;
- struct SCfgAgc *pRfAgcSettings;
+ struct s_cfg_agc *p_rf_agc_settings;
dprintk(1, "\n");
- switch (pAgcCfg->ctrlMode) {
+ switch (p_agc_cfg->ctrl_mode) {
case DRXK_AGC_CTRL_AUTO:
/* Enable IF AGC DAC */
@@ -2392,7 +2337,7 @@ static int SetAgcIf(struct drxk_state *state,
data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
/* Polarity */
- if (state->m_IfAgcPol)
+ if (state->m_if_agc_pol)
data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
else
data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
@@ -2405,7 +2350,7 @@ static int SetAgcIf(struct drxk_state *state,
if (status < 0)
goto error;
data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
- data |= (~(pAgcCfg->speed <<
+ data |= (~(p_agc_cfg->speed <<
SCU_RAM_AGC_KI_RED_IAGC_RED__B)
& SCU_RAM_AGC_KI_RED_IAGC_RED__M);
@@ -2413,14 +2358,15 @@ static int SetAgcIf(struct drxk_state *state,
if (status < 0)
goto error;
- if (IsQAM(state))
- pRfAgcSettings = &state->m_qamRfAgcCfg;
+ if (is_qam(state))
+ p_rf_agc_settings = &state->m_qam_rf_agc_cfg;
else
- pRfAgcSettings = &state->m_atvRfAgcCfg;
- if (pRfAgcSettings == NULL)
+ p_rf_agc_settings = &state->m_atv_rf_agc_cfg;
+ if (p_rf_agc_settings == NULL)
return -1;
/* Restore TOP */
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
+ status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+ p_rf_agc_settings->top);
if (status < 0)
goto error;
break;
@@ -2444,7 +2390,7 @@ static int SetAgcIf(struct drxk_state *state,
data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
/* Polarity */
- if (state->m_IfAgcPol)
+ if (state->m_if_agc_pol)
data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
else
data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
@@ -2453,7 +2399,8 @@ static int SetAgcIf(struct drxk_state *state,
goto error;
/* Write value to output pin */
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
+ status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+ p_agc_cfg->output_level);
if (status < 0)
goto error;
break;
@@ -2478,176 +2425,181 @@ static int SetAgcIf(struct drxk_state *state,
if (status < 0)
goto error;
break;
- } /* switch (agcSettingsIf->ctrlMode) */
+ } /* switch (agcSettingsIf->ctrl_mode) */
/* always set the top to support
configurations without if-loop */
- status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
+ status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, p_agc_cfg->top);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int GetQAMSignalToNoise(struct drxk_state *state,
- s32 *pSignalToNoise)
+static int get_qam_signal_to_noise(struct drxk_state *state,
+ s32 *p_signal_to_noise)
{
int status = 0;
- u16 qamSlErrPower = 0; /* accum. error between
+ u16 qam_sl_err_power = 0; /* accum. error between
raw and sliced symbols */
- u32 qamSlSigPower = 0; /* used for MER, depends of
+ u32 qam_sl_sig_power = 0; /* used for MER, depends of
QAM modulation */
- u32 qamSlMer = 0; /* QAM MER */
+ u32 qam_sl_mer = 0; /* QAM MER */
dprintk(1, "\n");
/* MER calculation */
/* get the register value needed for MER */
- status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
+ status = read16(state, QAM_SL_ERR_POWER__A, &qam_sl_err_power);
if (status < 0) {
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return -EINVAL;
}
switch (state->props.modulation) {
case QAM_16:
- qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
+ qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
break;
case QAM_32:
- qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
+ qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
break;
case QAM_64:
- qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
+ qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
break;
case QAM_128:
- qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
+ qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
break;
default:
case QAM_256:
- qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
+ qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
break;
}
- if (qamSlErrPower > 0) {
- qamSlMer = Log10Times100(qamSlSigPower) -
- Log10Times100((u32) qamSlErrPower);
+ if (qam_sl_err_power > 0) {
+ qam_sl_mer = log10times100(qam_sl_sig_power) -
+ log10times100((u32) qam_sl_err_power);
}
- *pSignalToNoise = qamSlMer;
+ *p_signal_to_noise = qam_sl_mer;
return status;
}
-static int GetDVBTSignalToNoise(struct drxk_state *state,
- s32 *pSignalToNoise)
+static int get_dvbt_signal_to_noise(struct drxk_state *state,
+ s32 *p_signal_to_noise)
{
int status;
- u16 regData = 0;
- u32 EqRegTdSqrErrI = 0;
- u32 EqRegTdSqrErrQ = 0;
- u16 EqRegTdSqrErrExp = 0;
- u16 EqRegTdTpsPwrOfs = 0;
- u16 EqRegTdReqSmbCnt = 0;
- u32 tpsCnt = 0;
- u32 SqrErrIQ = 0;
+ u16 reg_data = 0;
+ u32 eq_reg_td_sqr_err_i = 0;
+ u32 eq_reg_td_sqr_err_q = 0;
+ u16 eq_reg_td_sqr_err_exp = 0;
+ u16 eq_reg_td_tps_pwr_ofs = 0;
+ u16 eq_reg_td_req_smb_cnt = 0;
+ u32 tps_cnt = 0;
+ u32 sqr_err_iq = 0;
u32 a = 0;
u32 b = 0;
u32 c = 0;
- u32 iMER = 0;
- u16 transmissionParams = 0;
+ u32 i_mer = 0;
+ u16 transmission_params = 0;
dprintk(1, "\n");
- status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
+ status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A,
+ &eq_reg_td_tps_pwr_ofs);
if (status < 0)
goto error;
- status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
+ status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A,
+ &eq_reg_td_req_smb_cnt);
if (status < 0)
goto error;
- status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
+ status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A,
+ &eq_reg_td_sqr_err_exp);
if (status < 0)
goto error;
- status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
+ status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A,
+ &reg_data);
if (status < 0)
goto error;
/* Extend SQR_ERR_I operational range */
- EqRegTdSqrErrI = (u32) regData;
- if ((EqRegTdSqrErrExp > 11) &&
- (EqRegTdSqrErrI < 0x00000FFFUL)) {
- EqRegTdSqrErrI += 0x00010000UL;
+ eq_reg_td_sqr_err_i = (u32) reg_data;
+ if ((eq_reg_td_sqr_err_exp > 11) &&
+ (eq_reg_td_sqr_err_i < 0x00000FFFUL)) {
+ eq_reg_td_sqr_err_i += 0x00010000UL;
}
- status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
+ status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &reg_data);
if (status < 0)
goto error;
/* Extend SQR_ERR_Q operational range */
- EqRegTdSqrErrQ = (u32) regData;
- if ((EqRegTdSqrErrExp > 11) &&
- (EqRegTdSqrErrQ < 0x00000FFFUL))
- EqRegTdSqrErrQ += 0x00010000UL;
+ eq_reg_td_sqr_err_q = (u32) reg_data;
+ if ((eq_reg_td_sqr_err_exp > 11) &&
+ (eq_reg_td_sqr_err_q < 0x00000FFFUL))
+ eq_reg_td_sqr_err_q += 0x00010000UL;
- status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
+ status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A,
+ &transmission_params);
if (status < 0)
goto error;
/* Check input data for MER */
/* MER calculation (in 0.1 dB) without math.h */
- if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
- iMER = 0;
- else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
+ if ((eq_reg_td_tps_pwr_ofs == 0) || (eq_reg_td_req_smb_cnt == 0))
+ i_mer = 0;
+ else if ((eq_reg_td_sqr_err_i + eq_reg_td_sqr_err_q) == 0) {
/* No error at all, this must be the HW reset value
* Apparently no first measurement yet
* Set MER to 0.0 */
- iMER = 0;
+ i_mer = 0;
} else {
- SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
- EqRegTdSqrErrExp;
- if ((transmissionParams &
+ sqr_err_iq = (eq_reg_td_sqr_err_i + eq_reg_td_sqr_err_q) <<
+ eq_reg_td_sqr_err_exp;
+ if ((transmission_params &
OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
== OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
- tpsCnt = 17;
+ tps_cnt = 17;
else
- tpsCnt = 68;
+ tps_cnt = 68;
/* IMER = 100 * log10 (x)
- where x = (EqRegTdTpsPwrOfs^2 *
- EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
+ where x = (eq_reg_td_tps_pwr_ofs^2 *
+ eq_reg_td_req_smb_cnt * tps_cnt)/sqr_err_iq
=> IMER = a + b -c
- where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
- b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
- c = 100 * log10 (SqrErrIQ)
+ where a = 100 * log10 (eq_reg_td_tps_pwr_ofs^2)
+ b = 100 * log10 (eq_reg_td_req_smb_cnt * tps_cnt)
+ c = 100 * log10 (sqr_err_iq)
*/
/* log(x) x = 9bits * 9bits->18 bits */
- a = Log10Times100(EqRegTdTpsPwrOfs *
- EqRegTdTpsPwrOfs);
+ a = log10times100(eq_reg_td_tps_pwr_ofs *
+ eq_reg_td_tps_pwr_ofs);
/* log(x) x = 16bits * 7bits->23 bits */
- b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
+ b = log10times100(eq_reg_td_req_smb_cnt * tps_cnt);
/* log(x) x = (16bits + 16bits) << 15 ->32 bits */
- c = Log10Times100(SqrErrIQ);
+ c = log10times100(sqr_err_iq);
- iMER = a + b - c;
+ i_mer = a + b - c;
}
- *pSignalToNoise = iMER;
+ *p_signal_to_noise = i_mer;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
+static int get_signal_to_noise(struct drxk_state *state, s32 *p_signal_to_noise)
{
dprintk(1, "\n");
- *pSignalToNoise = 0;
- switch (state->m_OperationMode) {
+ *p_signal_to_noise = 0;
+ switch (state->m_operation_mode) {
case OM_DVBT:
- return GetDVBTSignalToNoise(state, pSignalToNoise);
+ return get_dvbt_signal_to_noise(state, p_signal_to_noise);
case OM_QAM_ITU_A:
case OM_QAM_ITU_C:
- return GetQAMSignalToNoise(state, pSignalToNoise);
+ return get_qam_signal_to_noise(state, p_signal_to_noise);
default:
break;
}
@@ -2655,7 +2607,7 @@ static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
}
#if 0
-static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
+static int get_dvbt_quality(struct drxk_state *state, s32 *p_quality)
{
/* SNR Values for quasi errorfree reception rom Nordig 2.2 */
int status = 0;
@@ -2680,102 +2632,104 @@ static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
225, /* 64-QAM 7/8 */
};
- *pQuality = 0;
+ *p_quality = 0;
do {
- s32 SignalToNoise = 0;
- u16 Constellation = 0;
- u16 CodeRate = 0;
- u32 SignalToNoiseRel;
- u32 BERQuality;
+ s32 signal_to_noise = 0;
+ u16 constellation = 0;
+ u16 code_rate = 0;
+ u32 signal_to_noise_rel;
+ u32 ber_quality;
- status = GetDVBTSignalToNoise(state, &SignalToNoise);
+ status = get_dvbt_signal_to_noise(state, &signal_to_noise);
if (status < 0)
break;
- status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
+ status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A,
+ &constellation);
if (status < 0)
break;
- Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
+ constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
- status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
+ status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A,
+ &code_rate);
if (status < 0)
break;
- CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
+ code_rate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
- if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
- CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
+ if (constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
+ code_rate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
break;
- SignalToNoiseRel = SignalToNoise -
- QE_SN[Constellation * 5 + CodeRate];
- BERQuality = 100;
-
- if (SignalToNoiseRel < -70)
- *pQuality = 0;
- else if (SignalToNoiseRel < 30)
- *pQuality = ((SignalToNoiseRel + 70) *
- BERQuality) / 100;
+ signal_to_noise_rel = signal_to_noise -
+ QE_SN[constellation * 5 + code_rate];
+ ber_quality = 100;
+
+ if (signal_to_noise_rel < -70)
+ *p_quality = 0;
+ else if (signal_to_noise_rel < 30)
+ *p_quality = ((signal_to_noise_rel + 70) *
+ ber_quality) / 100;
else
- *pQuality = BERQuality;
+ *p_quality = ber_quality;
} while (0);
return 0;
};
-static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
+static int get_dvbc_quality(struct drxk_state *state, s32 *p_quality)
{
int status = 0;
- *pQuality = 0;
+ *p_quality = 0;
dprintk(1, "\n");
do {
- u32 SignalToNoise = 0;
- u32 BERQuality = 100;
- u32 SignalToNoiseRel = 0;
+ u32 signal_to_noise = 0;
+ u32 ber_quality = 100;
+ u32 signal_to_noise_rel = 0;
- status = GetQAMSignalToNoise(state, &SignalToNoise);
+ status = get_qam_signal_to_noise(state, &signal_to_noise);
if (status < 0)
break;
switch (state->props.modulation) {
case QAM_16:
- SignalToNoiseRel = SignalToNoise - 200;
+ signal_to_noise_rel = signal_to_noise - 200;
break;
case QAM_32:
- SignalToNoiseRel = SignalToNoise - 230;
+ signal_to_noise_rel = signal_to_noise - 230;
break; /* Not in NorDig */
case QAM_64:
- SignalToNoiseRel = SignalToNoise - 260;
+ signal_to_noise_rel = signal_to_noise - 260;
break;
case QAM_128:
- SignalToNoiseRel = SignalToNoise - 290;
+ signal_to_noise_rel = signal_to_noise - 290;
break;
default:
case QAM_256:
- SignalToNoiseRel = SignalToNoise - 320;
+ signal_to_noise_rel = signal_to_noise - 320;
break;
}
- if (SignalToNoiseRel < -70)
- *pQuality = 0;
- else if (SignalToNoiseRel < 30)
- *pQuality = ((SignalToNoiseRel + 70) *
- BERQuality) / 100;
+ if (signal_to_noise_rel < -70)
+ *p_quality = 0;
+ else if (signal_to_noise_rel < 30)
+ *p_quality = ((signal_to_noise_rel + 70) *
+ ber_quality) / 100;
else
- *pQuality = BERQuality;
+ *p_quality = ber_quality;
} while (0);
return status;
}
-static int GetQuality(struct drxk_state *state, s32 *pQuality)
+static int get_quality(struct drxk_state *state, s32 *p_quality)
{
dprintk(1, "\n");
- switch (state->m_OperationMode) {
+ switch (state->m_operation_mode) {
case OM_DVBT:
- return GetDVBTQuality(state, pQuality);
+ return get_dvbt_quality(state, p_quality);
case OM_QAM_ITU_A:
- return GetDVBCQuality(state, pQuality);
+ return get_dvbc_quality(state, p_quality);
default:
break;
}
@@ -2797,65 +2751,68 @@ static int GetQuality(struct drxk_state *state, s32 *pQuality)
#define DRXDAP_FASI_ADDR2BANK(addr) (((addr) >> 16) & 0x3F)
#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
-static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
+static int ConfigureI2CBridge(struct drxk_state *state, bool b_enable_bridge)
{
int status = -EINVAL;
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return 0;
- if (state->m_DrxkState == DRXK_POWERED_DOWN)
+ if (state->m_drxk_state == DRXK_POWERED_DOWN)
goto error;
if (state->no_i2c_bridge)
return 0;
- status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+ status = write16(state, SIO_HI_RA_RAM_PAR_1__A,
+ SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
if (status < 0)
goto error;
- if (bEnableBridge) {
- status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
+ if (b_enable_bridge) {
+ status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+ SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
if (status < 0)
goto error;
} else {
- status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
+ status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+ SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
if (status < 0)
goto error;
}
- status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+ status = hi_command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SetPreSaw(struct drxk_state *state,
- struct SCfgPreSaw *pPreSawCfg)
+static int set_pre_saw(struct drxk_state *state,
+ struct s_cfg_pre_saw *p_pre_saw_cfg)
{
int status = -EINVAL;
dprintk(1, "\n");
- if ((pPreSawCfg == NULL)
- || (pPreSawCfg->reference > IQM_AF_PDREF__M))
+ if ((p_pre_saw_cfg == NULL)
+ || (p_pre_saw_cfg->reference > IQM_AF_PDREF__M))
goto error;
- status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
+ status = write16(state, IQM_AF_PDREF__A, p_pre_saw_cfg->reference);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
- u16 romOffset, u16 nrOfElements, u32 timeOut)
+static int bl_direct_cmd(struct drxk_state *state, u32 target_addr,
+ u16 rom_offset, u16 nr_of_elements, u32 time_out)
{
- u16 blStatus = 0;
- u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
- u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
+ u16 bl_status = 0;
+ u16 offset = (u16) ((target_addr >> 0) & 0x00FFFF);
+ u16 blockbank = (u16) ((target_addr >> 16) & 0x000FFF);
int status;
unsigned long end;
@@ -2871,44 +2828,44 @@ static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
status = write16(state, SIO_BL_TGT_ADDR__A, offset);
if (status < 0)
goto error;
- status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
+ status = write16(state, SIO_BL_SRC_ADDR__A, rom_offset);
if (status < 0)
goto error;
- status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
+ status = write16(state, SIO_BL_SRC_LEN__A, nr_of_elements);
if (status < 0)
goto error;
status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
if (status < 0)
goto error;
- end = jiffies + msecs_to_jiffies(timeOut);
+ end = jiffies + msecs_to_jiffies(time_out);
do {
- status = read16(state, SIO_BL_STATUS__A, &blStatus);
+ status = read16(state, SIO_BL_STATUS__A, &bl_status);
if (status < 0)
goto error;
- } while ((blStatus == 0x1) && time_is_after_jiffies(end));
- if (blStatus == 0x1) {
- printk(KERN_ERR "drxk: SIO not ready\n");
+ } while ((bl_status == 0x1) && time_is_after_jiffies(end));
+ if (bl_status == 0x1) {
+ pr_err("SIO not ready\n");
status = -EINVAL;
goto error2;
}
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
error2:
mutex_unlock(&state->mutex);
return status;
}
-static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
+static int adc_sync_measurement(struct drxk_state *state, u16 *count)
{
u16 data = 0;
int status;
dprintk(1, "\n");
- /* Start measurement */
+ /* start measurement */
status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
if (status < 0)
goto error;
@@ -2935,42 +2892,42 @@ static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int ADCSynchronization(struct drxk_state *state)
+static int adc_synchronization(struct drxk_state *state)
{
u16 count = 0;
int status;
dprintk(1, "\n");
- status = ADCSyncMeasurement(state, &count);
+ status = adc_sync_measurement(state, &count);
if (status < 0)
goto error;
if (count == 1) {
/* Try sampling on a diffrent edge */
- u16 clkNeg = 0;
+ u16 clk_neg = 0;
- status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
+ status = read16(state, IQM_AF_CLKNEG__A, &clk_neg);
if (status < 0)
goto error;
- if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+ if ((clk_neg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
- clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
- clkNeg |=
+ clk_neg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+ clk_neg |=
IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
} else {
- clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
- clkNeg |=
+ clk_neg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+ clk_neg |=
IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
}
- status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
+ status = write16(state, IQM_AF_CLKNEG__A, clk_neg);
if (status < 0)
goto error;
- status = ADCSyncMeasurement(state, &count);
+ status = adc_sync_measurement(state, &count);
if (status < 0)
goto error;
}
@@ -2979,25 +2936,25 @@ static int ADCSynchronization(struct drxk_state *state)
status = -EINVAL;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SetFrequencyShifter(struct drxk_state *state,
- u16 intermediateFreqkHz,
- s32 tunerFreqOffset, bool isDTV)
+static int set_frequency_shifter(struct drxk_state *state,
+ u16 intermediate_freqk_hz,
+ s32 tuner_freq_offset, bool is_dtv)
{
- bool selectPosImage = false;
- u32 rfFreqResidual = tunerFreqOffset;
- u32 fmFrequencyShift = 0;
- bool tunerMirror = !state->m_bMirrorFreqSpect;
- u32 adcFreq;
- bool adcFlip;
+ bool select_pos_image = false;
+ u32 rf_freq_residual = tuner_freq_offset;
+ u32 fm_frequency_shift = 0;
+ bool tuner_mirror = !state->m_b_mirror_freq_spect;
+ u32 adc_freq;
+ bool adc_flip;
int status;
- u32 ifFreqActual;
- u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
- u32 frequencyShift;
- bool imageToSelect;
+ u32 if_freq_actual;
+ u32 sampling_frequency = (u32) (state->m_sys_clock_freq / 3);
+ u32 frequency_shift;
+ bool image_to_select;
dprintk(1, "\n");
@@ -3005,121 +2962,125 @@ static int SetFrequencyShifter(struct drxk_state *state,
Program frequency shifter
No need to account for mirroring on RF
*/
- if (isDTV) {
- if ((state->m_OperationMode == OM_QAM_ITU_A) ||
- (state->m_OperationMode == OM_QAM_ITU_C) ||
- (state->m_OperationMode == OM_DVBT))
- selectPosImage = true;
+ if (is_dtv) {
+ if ((state->m_operation_mode == OM_QAM_ITU_A) ||
+ (state->m_operation_mode == OM_QAM_ITU_C) ||
+ (state->m_operation_mode == OM_DVBT))
+ select_pos_image = true;
else
- selectPosImage = false;
+ select_pos_image = false;
}
- if (tunerMirror)
+ if (tuner_mirror)
/* tuner doesn't mirror */
- ifFreqActual = intermediateFreqkHz +
- rfFreqResidual + fmFrequencyShift;
+ if_freq_actual = intermediate_freqk_hz +
+ rf_freq_residual + fm_frequency_shift;
else
/* tuner mirrors */
- ifFreqActual = intermediateFreqkHz -
- rfFreqResidual - fmFrequencyShift;
- if (ifFreqActual > samplingFrequency / 2) {
+ if_freq_actual = intermediate_freqk_hz -
+ rf_freq_residual - fm_frequency_shift;
+ if (if_freq_actual > sampling_frequency / 2) {
/* adc mirrors */
- adcFreq = samplingFrequency - ifFreqActual;
- adcFlip = true;
+ adc_freq = sampling_frequency - if_freq_actual;
+ adc_flip = true;
} else {
/* adc doesn't mirror */
- adcFreq = ifFreqActual;
- adcFlip = false;
+ adc_freq = if_freq_actual;
+ adc_flip = false;
}
- frequencyShift = adcFreq;
- imageToSelect = state->m_rfmirror ^ tunerMirror ^
- adcFlip ^ selectPosImage;
- state->m_IqmFsRateOfs =
- Frac28a((frequencyShift), samplingFrequency);
+ frequency_shift = adc_freq;
+ image_to_select = state->m_rfmirror ^ tuner_mirror ^
+ adc_flip ^ select_pos_image;
+ state->m_iqm_fs_rate_ofs =
+ Frac28a((frequency_shift), sampling_frequency);
- if (imageToSelect)
- state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
+ if (image_to_select)
+ state->m_iqm_fs_rate_ofs = ~state->m_iqm_fs_rate_ofs + 1;
/* Program frequency shifter with tuner offset compensation */
- /* frequencyShift += tunerFreqOffset; TODO */
+ /* frequency_shift += tuner_freq_offset; TODO */
status = write32(state, IQM_FS_RATE_OFS_LO__A,
- state->m_IqmFsRateOfs);
+ state->m_iqm_fs_rate_ofs);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int InitAGC(struct drxk_state *state, bool isDTV)
+static int init_agc(struct drxk_state *state, bool is_dtv)
{
- u16 ingainTgt = 0;
- u16 ingainTgtMin = 0;
- u16 ingainTgtMax = 0;
- u16 clpCyclen = 0;
- u16 clpSumMin = 0;
- u16 clpDirTo = 0;
- u16 snsSumMin = 0;
- u16 snsSumMax = 0;
- u16 clpSumMax = 0;
- u16 snsDirTo = 0;
- u16 kiInnergainMin = 0;
- u16 ifIaccuHiTgt = 0;
- u16 ifIaccuHiTgtMin = 0;
- u16 ifIaccuHiTgtMax = 0;
+ u16 ingain_tgt = 0;
+ u16 ingain_tgt_min = 0;
+ u16 ingain_tgt_max = 0;
+ u16 clp_cyclen = 0;
+ u16 clp_sum_min = 0;
+ u16 clp_dir_to = 0;
+ u16 sns_sum_min = 0;
+ u16 sns_sum_max = 0;
+ u16 clp_sum_max = 0;
+ u16 sns_dir_to = 0;
+ u16 ki_innergain_min = 0;
+ u16 if_iaccu_hi_tgt = 0;
+ u16 if_iaccu_hi_tgt_min = 0;
+ u16 if_iaccu_hi_tgt_max = 0;
u16 data = 0;
- u16 fastClpCtrlDelay = 0;
- u16 clpCtrlMode = 0;
+ u16 fast_clp_ctrl_delay = 0;
+ u16 clp_ctrl_mode = 0;
int status = 0;
dprintk(1, "\n");
/* Common settings */
- snsSumMax = 1023;
- ifIaccuHiTgtMin = 2047;
- clpCyclen = 500;
- clpSumMax = 1023;
+ sns_sum_max = 1023;
+ if_iaccu_hi_tgt_min = 2047;
+ clp_cyclen = 500;
+ clp_sum_max = 1023;
/* AGCInit() not available for DVBT; init done in microcode */
- if (!IsQAM(state)) {
- printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
+ if (!is_qam(state)) {
+ pr_err("%s: mode %d is not DVB-C\n",
+ __func__, state->m_operation_mode);
return -EINVAL;
}
/* FIXME: Analog TV AGC require different settings */
/* Standard specific settings */
- clpSumMin = 8;
- clpDirTo = (u16) -9;
- clpCtrlMode = 0;
- snsSumMin = 8;
- snsDirTo = (u16) -9;
- kiInnergainMin = (u16) -1030;
- ifIaccuHiTgtMax = 0x2380;
- ifIaccuHiTgt = 0x2380;
- ingainTgtMin = 0x0511;
- ingainTgt = 0x0511;
- ingainTgtMax = 5119;
- fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
+ clp_sum_min = 8;
+ clp_dir_to = (u16) -9;
+ clp_ctrl_mode = 0;
+ sns_sum_min = 8;
+ sns_dir_to = (u16) -9;
+ ki_innergain_min = (u16) -1030;
+ if_iaccu_hi_tgt_max = 0x2380;
+ if_iaccu_hi_tgt = 0x2380;
+ ingain_tgt_min = 0x0511;
+ ingain_tgt = 0x0511;
+ ingain_tgt_max = 5119;
+ fast_clp_ctrl_delay = state->m_qam_if_agc_cfg.fast_clip_ctrl_delay;
- status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
+ status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A,
+ fast_clp_ctrl_delay);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
+ status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clp_ctrl_mode);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
+ status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingain_tgt);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
+ status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingain_tgt_min);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
+ status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingain_tgt_max);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
+ status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A,
+ if_iaccu_hi_tgt_min);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
+ status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+ if_iaccu_hi_tgt_max);
if (status < 0)
goto error;
status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
@@ -3134,20 +3095,22 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
+ status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clp_sum_max);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
+ status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, sns_sum_max);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
+ status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A,
+ ki_innergain_min);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
+ status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A,
+ if_iaccu_hi_tgt);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
+ status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clp_cyclen);
if (status < 0)
goto error;
@@ -3164,16 +3127,16 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
+ status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clp_sum_min);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
+ status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, sns_sum_min);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
+ status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clp_dir_to);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
+ status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, sns_dir_to);
if (status < 0)
goto error;
status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
@@ -3233,38 +3196,39 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
status = write16(state, SCU_RAM_AGC_KI__A, data);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
+static int dvbtqam_get_acc_pkt_err(struct drxk_state *state, u16 *packet_err)
{
int status;
dprintk(1, "\n");
- if (packetErr == NULL)
+ if (packet_err == NULL)
status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
else
- status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
+ status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A,
+ packet_err);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int DVBTScCommand(struct drxk_state *state,
+static int dvbt_sc_command(struct drxk_state *state,
u16 cmd, u16 subcmd,
u16 param0, u16 param1, u16 param2,
u16 param3, u16 param4)
{
- u16 curCmd = 0;
- u16 errCode = 0;
- u16 retryCnt = 0;
- u16 scExec = 0;
+ u16 cur_cmd = 0;
+ u16 err_code = 0;
+ u16 retry_cnt = 0;
+ u16 sc_exec = 0;
int status;
dprintk(1, "\n");
- status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
- if (scExec != 1) {
+ status = read16(state, OFDM_SC_COMM_EXEC__A, &sc_exec);
+ if (sc_exec != 1) {
/* SC is not running */
status = -EINVAL;
}
@@ -3272,13 +3236,13 @@ static int DVBTScCommand(struct drxk_state *state,
goto error;
/* Wait until sc is ready to receive command */
- retryCnt = 0;
+ retry_cnt = 0;
do {
- msleep(1);
- status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
- retryCnt++;
- } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
- if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+ usleep_range(1000, 2000);
+ status = read16(state, OFDM_SC_RA_RAM_CMD__A, &cur_cmd);
+ retry_cnt++;
+ } while ((cur_cmd != 0) && (retry_cnt < DRXK_MAX_RETRIES));
+ if (retry_cnt >= DRXK_MAX_RETRIES && (status < 0))
goto error;
/* Write sub-command */
@@ -3324,18 +3288,18 @@ static int DVBTScCommand(struct drxk_state *state,
goto error;
/* Wait until sc is ready processing command */
- retryCnt = 0;
+ retry_cnt = 0;
do {
- msleep(1);
- status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
- retryCnt++;
- } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
- if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+ usleep_range(1000, 2000);
+ status = read16(state, OFDM_SC_RA_RAM_CMD__A, &cur_cmd);
+ retry_cnt++;
+ } while ((cur_cmd != 0) && (retry_cnt < DRXK_MAX_RETRIES));
+ if (retry_cnt >= DRXK_MAX_RETRIES && (status < 0))
goto error;
/* Check for illegal cmd */
- status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
- if (errCode == 0xFFFF) {
+ status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &err_code);
+ if (err_code == 0xFFFF) {
/* illegal command */
status = -EINVAL;
}
@@ -3367,23 +3331,23 @@ static int DVBTScCommand(struct drxk_state *state,
} /* switch (cmd->cmd) */
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int PowerUpDVBT(struct drxk_state *state)
+static int power_up_dvbt(struct drxk_state *state)
{
- enum DRXPowerMode powerMode = DRX_POWER_UP;
+ enum drx_power_mode power_mode = DRX_POWER_UP;
int status;
dprintk(1, "\n");
- status = CtrlPowerMode(state, &powerMode);
+ status = ctrl_power_mode(state, &power_mode);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
+static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled)
{
int status;
@@ -3393,12 +3357,12 @@ static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
else
status = write16(state, IQM_CF_BYPASSDET__A, 1);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
#define DEFAULT_FR_THRES_8K 4000
-static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
+static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled)
{
int status;
@@ -3413,13 +3377,13 @@ static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
}
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
- struct DRXKCfgDvbtEchoThres_t *echoThres)
+static int dvbt_ctrl_set_echo_threshold(struct drxk_state *state,
+ struct drxk_cfg_dvbt_echo_thres_t *echo_thres)
{
u16 data = 0;
int status;
@@ -3429,16 +3393,16 @@ static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
if (status < 0)
goto error;
- switch (echoThres->fftMode) {
+ switch (echo_thres->fft_mode) {
case DRX_FFTMODE_2K:
data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
- data |= ((echoThres->threshold <<
+ data |= ((echo_thres->threshold <<
OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
& (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
break;
case DRX_FFTMODE_8K:
data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
- data |= ((echoThres->threshold <<
+ data |= ((echo_thres->threshold <<
OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
& (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
break;
@@ -3449,12 +3413,12 @@ static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
- enum DRXKCfgDvbtSqiSpeed *speed)
+static int dvbt_ctrl_set_sqi_speed(struct drxk_state *state,
+ enum drxk_cfg_dvbt_sqi_speed *speed)
{
int status = -EINVAL;
@@ -3472,7 +3436,7 @@ static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
(u16) *speed);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -3486,32 +3450,33 @@ error:
* Called in DVBTSetStandard
*
*/
-static int DVBTActivatePresets(struct drxk_state *state)
+static int dvbt_activate_presets(struct drxk_state *state)
{
int status;
bool setincenable = false;
bool setfrenable = true;
- struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
- struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
+ struct drxk_cfg_dvbt_echo_thres_t echo_thres2k = { 0, DRX_FFTMODE_2K };
+ struct drxk_cfg_dvbt_echo_thres_t echo_thres8k = { 0, DRX_FFTMODE_8K };
dprintk(1, "\n");
- status = DVBTCtrlSetIncEnable(state, &setincenable);
+ status = dvbt_ctrl_set_inc_enable(state, &setincenable);
if (status < 0)
goto error;
- status = DVBTCtrlSetFrEnable(state, &setfrenable);
+ status = dvbt_ctrl_set_fr_enable(state, &setfrenable);
if (status < 0)
goto error;
- status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
+ status = dvbt_ctrl_set_echo_threshold(state, &echo_thres2k);
if (status < 0)
goto error;
- status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
+ status = dvbt_ctrl_set_echo_threshold(state, &echo_thres8k);
if (status < 0)
goto error;
- status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
+ status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A,
+ state->m_dvbt_if_agc_cfg.ingain_tgt_max);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -3525,25 +3490,30 @@ error:
* For ROM code channel filter taps are loaded from the bootloader. For microcode
* the DVB-T taps from the drxk_filters.h are used.
*/
-static int SetDVBTStandard(struct drxk_state *state,
- enum OperationMode oMode)
+static int set_dvbt_standard(struct drxk_state *state,
+ enum operation_mode o_mode)
{
- u16 cmdResult = 0;
+ u16 cmd_result = 0;
u16 data = 0;
int status;
dprintk(1, "\n");
- PowerUpDVBT(state);
+ power_up_dvbt(state);
/* added antenna switch */
- SwitchAntennaToDVBT(state);
+ switch_antenna_to_dvbt(state);
/* send OFDM reset command */
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+ status = scu_command(state,
+ SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
/* send OFDM setenv command */
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
@@ -3575,7 +3545,7 @@ static int SetDVBTStandard(struct drxk_state *state,
status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
if (status < 0)
goto error;
- status = SetIqmAf(state, true);
+ status = set_iqm_af(state, true);
if (status < 0)
goto error;
@@ -3597,7 +3567,7 @@ static int SetDVBTStandard(struct drxk_state *state,
status = write16(state, IQM_RC_STRETCH__A, 16);
if (status < 0)
goto error;
- status = write16(state, IQM_CF_OUT_ENA__A, 0x4); /* enable output 2 */
+ status = write16(state, IQM_CF_OUT_ENA__A, 0x4); /* enable output 2 */
if (status < 0)
goto error;
status = write16(state, IQM_CF_DS_ENA__A, 0x4); /* decimate output 2 */
@@ -3618,7 +3588,8 @@ static int SetDVBTStandard(struct drxk_state *state,
if (status < 0)
goto error;
- status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+ status = bl_chain_cmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT,
+ DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
if (status < 0)
goto error;
@@ -3637,10 +3608,10 @@ static int SetDVBTStandard(struct drxk_state *state,
goto error;
/* IQM will not be reset from here, sync ADC and update/init AGC */
- status = ADCSynchronization(state);
+ status = adc_synchronization(state);
if (status < 0)
goto error;
- status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
+ status = set_pre_saw(state, &state->m_dvbt_pre_saw_cfg);
if (status < 0)
goto error;
@@ -3649,10 +3620,10 @@ static int SetDVBTStandard(struct drxk_state *state,
if (status < 0)
goto error;
- status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
+ status = set_agc_rf(state, &state->m_dvbt_rf_agc_cfg, true);
if (status < 0)
goto error;
- status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
+ status = set_agc_if(state, &state->m_dvbt_if_agc_cfg, true);
if (status < 0)
goto error;
@@ -3670,9 +3641,10 @@ static int SetDVBTStandard(struct drxk_state *state,
if (status < 0)
goto error;
- if (!state->m_DRXK_A3_ROM_CODE) {
- /* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay */
- status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
+ if (!state->m_drxk_a3_rom_code) {
+ /* AGCInit() is not done for DVBT, so set agcfast_clip_ctrl_delay */
+ status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A,
+ state->m_dvbt_if_agc_cfg.fast_clip_ctrl_delay);
if (status < 0)
goto error;
}
@@ -3707,41 +3679,43 @@ static int SetDVBTStandard(struct drxk_state *state,
goto error;
/* Setup MPEG bus */
- status = MPEGTSDtoSetup(state, OM_DVBT);
+ status = mpegts_dto_setup(state, OM_DVBT);
if (status < 0)
goto error;
/* Set DVBT Presets */
- status = DVBTActivatePresets(state);
+ status = dvbt_activate_presets(state);
if (status < 0)
goto error;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
/*============================================================================*/
/**
-* \brief Start dvbt demodulating for channel.
+* \brief start dvbt demodulating for channel.
* \param demod instance of demodulator.
* \return DRXStatus_t.
*/
-static int DVBTStart(struct drxk_state *state)
+static int dvbt_start(struct drxk_state *state)
{
u16 param1;
int status;
- /* DRXKOfdmScCmd_t scCmd; */
+ /* drxk_ofdm_sc_cmd_t scCmd; */
dprintk(1, "\n");
- /* Start correct processes to get in lock */
+ /* start correct processes to get in lock */
/* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
- status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
+ status = dvbt_sc_command(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0,
+ OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1,
+ 0, 0, 0);
if (status < 0)
goto error;
- /* Start FEC OC */
- status = MPEGTSStart(state);
+ /* start FEC OC */
+ status = mpegts_start(state);
if (status < 0)
goto error;
status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
@@ -3749,7 +3723,7 @@ static int DVBTStart(struct drxk_state *state)
goto error;
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -3762,20 +3736,23 @@ error:
* \return DRXStatus_t.
* // original DVBTSetChannel()
*/
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
- s32 tunerFreqOffset)
+static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
+ s32 tuner_freq_offset)
{
- u16 cmdResult = 0;
- u16 transmissionParams = 0;
- u16 operationMode = 0;
- u32 iqmRcRateOfs = 0;
+ u16 cmd_result = 0;
+ u16 transmission_params = 0;
+ u16 operation_mode = 0;
+ u32 iqm_rc_rate_ofs = 0;
u32 bandwidth = 0;
u16 param1;
int status;
- dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
+ dprintk(1, "IF =%d, TFO = %d\n",
+ intermediate_freqk_hz, tuner_freq_offset);
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
@@ -3798,19 +3775,19 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
if (status < 0)
goto error;
- /*== Write channel settings to device =====================================*/
+ /*== Write channel settings to device ================================*/
/* mode */
switch (state->props.transmission_mode) {
case TRANSMISSION_MODE_AUTO:
default:
- operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
+ operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
/* fall through , try first guess DRX_FFTMODE_8K */
case TRANSMISSION_MODE_8K:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
break;
case TRANSMISSION_MODE_2K:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
break;
}
@@ -3818,19 +3795,19 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
switch (state->props.guard_interval) {
default:
case GUARD_INTERVAL_AUTO:
- operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
+ operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
/* fall through , try first guess DRX_GUARD_1DIV4 */
case GUARD_INTERVAL_1_4:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
break;
case GUARD_INTERVAL_1_32:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
break;
case GUARD_INTERVAL_1_16:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
break;
case GUARD_INTERVAL_1_8:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
break;
}
@@ -3839,18 +3816,18 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
case HIERARCHY_AUTO:
case HIERARCHY_NONE:
default:
- operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
+ operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
/* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
- /* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
+ /* transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
/* break; */
case HIERARCHY_1:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
break;
case HIERARCHY_2:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
break;
case HIERARCHY_4:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
break;
}
@@ -3859,16 +3836,16 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
switch (state->props.modulation) {
case QAM_AUTO:
default:
- operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
+ operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
/* fall through , try first guess DRX_CONSTELLATION_QAM64 */
case QAM_64:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
break;
case QPSK:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
break;
case QAM_16:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
break;
}
#if 0
@@ -3876,13 +3853,13 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
/* Priority (only for hierarchical channels) */
switch (channel->priority) {
case DRX_PRIORITY_LOW:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
- WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
+ WR16(dev_addr, OFDM_EC_SB_PRIOR__A,
OFDM_EC_SB_PRIOR_LO);
break;
case DRX_PRIORITY_HIGH:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
- WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+ WR16(dev_addr, OFDM_EC_SB_PRIOR__A,
OFDM_EC_SB_PRIOR_HI));
break;
case DRX_PRIORITY_UNKNOWN: /* fall through */
@@ -3892,7 +3869,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
}
#else
/* Set Priorty high */
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
if (status < 0)
goto error;
@@ -3902,90 +3879,111 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
switch (state->props.code_rate_HP) {
case FEC_AUTO:
default:
- operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
+ operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
/* fall through , try first guess DRX_CODERATE_2DIV3 */
case FEC_2_3:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
break;
case FEC_1_2:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
break;
case FEC_3_4:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
break;
case FEC_5_6:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
break;
case FEC_7_8:
- transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
+ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
break;
}
- /* SAW filter selection: normaly not necesarry, but if wanted
- the application can select a SAW filter via the driver by using UIOs */
+ /*
+ * SAW filter selection: normaly not necesarry, but if wanted
+ * the application can select a SAW filter via the driver by
+ * using UIOs
+ */
+
/* First determine real bandwidth (Hz) */
/* Also set delay for impulse noise cruncher */
- /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
- by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
- functions */
+ /*
+ * Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is
+ * changed by SC for fix for some 8K,1/8 guard but is restored by
+ * InitEC and ResetEC functions
+ */
switch (state->props.bandwidth_hz) {
case 0:
state->props.bandwidth_hz = 8000000;
/* fall though */
case 8000000:
bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
- status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
+ status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+ 3052);
if (status < 0)
goto error;
/* cochannel protection for PAL 8 MHz */
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+ 7);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+ 7);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+ 7);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+ 1);
if (status < 0)
goto error;
break;
case 7000000:
bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
- status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
+ status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+ 3491);
if (status < 0)
goto error;
/* cochannel protection for PAL 7 MHz */
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+ 8);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+ 8);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+ 4);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+ 1);
if (status < 0)
goto error;
break;
case 6000000:
bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
- status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
+ status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+ 4073);
if (status < 0)
goto error;
/* cochannel protection for NTSC 6 MHz */
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+ 19);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+ 19);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+ 14);
if (status < 0)
goto error;
- status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+ status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+ 1);
if (status < 0)
goto error;
break;
@@ -3994,46 +3992,50 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
}
- if (iqmRcRateOfs == 0) {
+ if (iqm_rc_rate_ofs == 0) {
/* Now compute IQM_RC_RATE_OFS
(((SysFreq/BandWidth)/2)/2) -1) * 2^23)
=>
((SysFreq / BandWidth) * (2^21)) - (2^23)
*/
/* (SysFreq / BandWidth) * (2^28) */
- /* assert (MAX(sysClk)/MIN(bandwidth) < 16)
- => assert(MAX(sysClk) < 16*MIN(bandwidth))
- => assert(109714272 > 48000000) = true so Frac 28 can be used */
- iqmRcRateOfs = Frac28a((u32)
- ((state->m_sysClockFreq *
+ /*
+ * assert (MAX(sysClk)/MIN(bandwidth) < 16)
+ * => assert(MAX(sysClk) < 16*MIN(bandwidth))
+ * => assert(109714272 > 48000000) = true
+ * so Frac 28 can be used
+ */
+ iqm_rc_rate_ofs = Frac28a((u32)
+ ((state->m_sys_clock_freq *
1000) / 3), bandwidth);
- /* (SysFreq / BandWidth) * (2^21), rounding before truncating */
- if ((iqmRcRateOfs & 0x7fL) >= 0x40)
- iqmRcRateOfs += 0x80L;
- iqmRcRateOfs = iqmRcRateOfs >> 7;
+ /* (SysFreq / BandWidth) * (2^21), rounding before truncating */
+ if ((iqm_rc_rate_ofs & 0x7fL) >= 0x40)
+ iqm_rc_rate_ofs += 0x80L;
+ iqm_rc_rate_ofs = iqm_rc_rate_ofs >> 7;
/* ((SysFreq / BandWidth) * (2^21)) - (2^23) */
- iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
+ iqm_rc_rate_ofs = iqm_rc_rate_ofs - (1 << 23);
}
- iqmRcRateOfs &=
+ iqm_rc_rate_ofs &=
((((u32) IQM_RC_RATE_OFS_HI__M) <<
IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
- status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
+ status = write32(state, IQM_RC_RATE_OFS_LO__A, iqm_rc_rate_ofs);
if (status < 0)
goto error;
/* Bandwidth setting done */
#if 0
- status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
+ status = dvbt_set_frequency_shift(demod, channel, tuner_offset);
if (status < 0)
goto error;
#endif
- status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+ status = set_frequency_shifter(state, intermediate_freqk_hz,
+ tuner_freq_offset, true);
if (status < 0)
goto error;
- /*== Start SC, write channel settings to SC ===============================*/
+ /*== start SC, write channel settings to SC ==========================*/
/* Activate SCU to enable SCU commands */
status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
@@ -4049,7 +4051,9 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+ | SCU_RAM_COMMAND_CMD_DEMOD_START,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
@@ -4059,16 +4063,16 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
- status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
- 0, transmissionParams, param1, 0, 0, 0);
+ status = dvbt_sc_command(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
+ 0, transmission_params, param1, 0, 0, 0);
if (status < 0)
goto error;
- if (!state->m_DRXK_A3_ROM_CODE)
- status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
+ if (!state->m_drxk_a3_rom_code)
+ status = dvbt_ctrl_set_sqi_speed(state, &state->m_sqi_speed);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -4083,7 +4087,7 @@ error:
* \return DRXStatus_t.
*
*/
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_dvbt_lock_status(struct drxk_state *state, u32 *p_lock_status)
{
int status;
const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
@@ -4091,58 +4095,58 @@ static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
- u16 ScRaRamLock = 0;
- u16 ScCommExec = 0;
+ u16 sc_ra_ram_lock = 0;
+ u16 sc_comm_exec = 0;
dprintk(1, "\n");
- *pLockStatus = NOT_LOCKED;
+ *p_lock_status = NOT_LOCKED;
/* driver 0.9.0 */
/* Check if SC is running */
- status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
+ status = read16(state, OFDM_SC_COMM_EXEC__A, &sc_comm_exec);
if (status < 0)
goto end;
- if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
+ if (sc_comm_exec == OFDM_SC_COMM_EXEC_STOP)
goto end;
- status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
+ status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &sc_ra_ram_lock);
if (status < 0)
goto end;
- if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
- *pLockStatus = MPEG_LOCK;
- else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
- *pLockStatus = FEC_LOCK;
- else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
- *pLockStatus = DEMOD_LOCK;
- else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
- *pLockStatus = NEVER_LOCK;
+ if ((sc_ra_ram_lock & mpeg_lock_mask) == mpeg_lock_mask)
+ *p_lock_status = MPEG_LOCK;
+ else if ((sc_ra_ram_lock & fec_lock_mask) == fec_lock_mask)
+ *p_lock_status = FEC_LOCK;
+ else if ((sc_ra_ram_lock & demod_lock_mask) == demod_lock_mask)
+ *p_lock_status = DEMOD_LOCK;
+ else if (sc_ra_ram_lock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
+ *p_lock_status = NEVER_LOCK;
end:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int PowerUpQAM(struct drxk_state *state)
+static int power_up_qam(struct drxk_state *state)
{
- enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+ enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
int status;
dprintk(1, "\n");
- status = CtrlPowerMode(state, &powerMode);
+ status = ctrl_power_mode(state, &power_mode);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
/** Power Down QAM */
-static int PowerDownQAM(struct drxk_state *state)
+static int power_down_qam(struct drxk_state *state)
{
u16 data = 0;
- u16 cmdResult;
+ u16 cmd_result;
int status = 0;
dprintk(1, "\n");
@@ -4158,16 +4162,18 @@ static int PowerDownQAM(struct drxk_state *state)
status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
if (status < 0)
goto error;
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
}
/* powerdown AFE */
- status = SetIqmAf(state, false);
+ status = set_iqm_af(state, false);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -4185,20 +4191,20 @@ error:
* The implementation does not check this.
*
*/
-static int SetQAMMeasurement(struct drxk_state *state,
- enum EDrxkConstellation modulation,
- u32 symbolRate)
+static int set_qam_measurement(struct drxk_state *state,
+ enum e_drxk_constellation modulation,
+ u32 symbol_rate)
{
- u32 fecBitsDesired = 0; /* BER accounting period */
- u32 fecRsPeriodTotal = 0; /* Total period */
- u16 fecRsPrescale = 0; /* ReedSolomon Measurement Prescale */
- u16 fecRsPeriod = 0; /* Value for corresponding I2C register */
+ u32 fec_bits_desired = 0; /* BER accounting period */
+ u32 fec_rs_period_total = 0; /* Total period */
+ u16 fec_rs_prescale = 0; /* ReedSolomon Measurement Prescale */
+ u16 fec_rs_period = 0; /* Value for corresponding I2C register */
int status = 0;
dprintk(1, "\n");
- fecRsPrescale = 1;
- /* fecBitsDesired = symbolRate [kHz] *
+ fec_rs_prescale = 1;
+ /* fec_bits_desired = symbol_rate [kHz] *
FrameLenght [ms] *
(modulation + 1) *
SyncLoss (== 1) *
@@ -4206,19 +4212,19 @@ static int SetQAMMeasurement(struct drxk_state *state,
*/
switch (modulation) {
case DRX_CONSTELLATION_QAM16:
- fecBitsDesired = 4 * symbolRate;
+ fec_bits_desired = 4 * symbol_rate;
break;
case DRX_CONSTELLATION_QAM32:
- fecBitsDesired = 5 * symbolRate;
+ fec_bits_desired = 5 * symbol_rate;
break;
case DRX_CONSTELLATION_QAM64:
- fecBitsDesired = 6 * symbolRate;
+ fec_bits_desired = 6 * symbol_rate;
break;
case DRX_CONSTELLATION_QAM128:
- fecBitsDesired = 7 * symbolRate;
+ fec_bits_desired = 7 * symbol_rate;
break;
case DRX_CONSTELLATION_QAM256:
- fecBitsDesired = 8 * symbolRate;
+ fec_bits_desired = 8 * symbol_rate;
break;
default:
status = -EINVAL;
@@ -4226,40 +4232,41 @@ static int SetQAMMeasurement(struct drxk_state *state,
if (status < 0)
goto error;
- fecBitsDesired /= 1000; /* symbolRate [Hz] -> symbolRate [kHz] */
- fecBitsDesired *= 500; /* meas. period [ms] */
+ fec_bits_desired /= 1000; /* symbol_rate [Hz] -> symbol_rate [kHz] */
+ fec_bits_desired *= 500; /* meas. period [ms] */
/* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
- /* fecRsPeriodTotal = fecBitsDesired / 1632 */
- fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1; /* roughly ceil */
+ /* fec_rs_period_total = fec_bits_desired / 1632 */
+ fec_rs_period_total = (fec_bits_desired / 1632UL) + 1; /* roughly ceil */
- /* fecRsPeriodTotal = fecRsPrescale * fecRsPeriod */
- fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
- if (fecRsPrescale == 0) {
+ /* fec_rs_period_total = fec_rs_prescale * fec_rs_period */
+ fec_rs_prescale = 1 + (u16) (fec_rs_period_total >> 16);
+ if (fec_rs_prescale == 0) {
/* Divide by zero (though impossible) */
status = -EINVAL;
if (status < 0)
goto error;
}
- fecRsPeriod =
- ((u16) fecRsPeriodTotal +
- (fecRsPrescale >> 1)) / fecRsPrescale;
+ fec_rs_period =
+ ((u16) fec_rs_period_total +
+ (fec_rs_prescale >> 1)) / fec_rs_prescale;
/* write corresponding registers */
- status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
+ status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fec_rs_period);
if (status < 0)
goto error;
- status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
+ status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A,
+ fec_rs_prescale);
if (status < 0)
goto error;
- status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
+ status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fec_rs_period);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SetQAM16(struct drxk_state *state)
+static int set_qam16(struct drxk_state *state)
{
int status = 0;
@@ -4315,7 +4322,8 @@ static int SetQAM16(struct drxk_state *state)
goto error;
/* QAM Slicer Settings */
- status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
+ status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+ DRXK_QAM_SL_SIG_POWER_QAM16);
if (status < 0)
goto error;
@@ -4441,7 +4449,7 @@ static int SetQAM16(struct drxk_state *state)
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -4452,7 +4460,7 @@ error:
* \param demod instance of demod.
* \return DRXStatus_t.
*/
-static int SetQAM32(struct drxk_state *state)
+static int set_qam32(struct drxk_state *state)
{
int status = 0;
@@ -4511,7 +4519,8 @@ static int SetQAM32(struct drxk_state *state)
/* QAM Slicer Settings */
- status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
+ status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+ DRXK_QAM_SL_SIG_POWER_QAM32);
if (status < 0)
goto error;
@@ -4636,7 +4645,7 @@ static int SetQAM32(struct drxk_state *state)
status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -4647,7 +4656,7 @@ error:
* \param demod instance of demod.
* \return DRXStatus_t.
*/
-static int SetQAM64(struct drxk_state *state)
+static int set_qam64(struct drxk_state *state)
{
int status = 0;
@@ -4704,7 +4713,8 @@ static int SetQAM64(struct drxk_state *state)
goto error;
/* QAM Slicer Settings */
- status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
+ status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+ DRXK_QAM_SL_SIG_POWER_QAM64);
if (status < 0)
goto error;
@@ -4829,7 +4839,7 @@ static int SetQAM64(struct drxk_state *state)
status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -4841,7 +4851,7 @@ error:
* \param demod: instance of demod.
* \return DRXStatus_t.
*/
-static int SetQAM128(struct drxk_state *state)
+static int set_qam128(struct drxk_state *state)
{
int status = 0;
@@ -4900,7 +4910,8 @@ static int SetQAM128(struct drxk_state *state)
/* QAM Slicer Settings */
- status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
+ status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+ DRXK_QAM_SL_SIG_POWER_QAM128);
if (status < 0)
goto error;
@@ -5025,7 +5036,7 @@ static int SetQAM128(struct drxk_state *state)
status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -5037,7 +5048,7 @@ error:
* \param demod: instance of demod.
* \return DRXStatus_t.
*/
-static int SetQAM256(struct drxk_state *state)
+static int set_qam256(struct drxk_state *state)
{
int status = 0;
@@ -5095,7 +5106,8 @@ static int SetQAM256(struct drxk_state *state)
/* QAM Slicer Settings */
- status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
+ status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+ DRXK_QAM_SL_SIG_POWER_QAM256);
if (status < 0)
goto error;
@@ -5220,7 +5232,7 @@ static int SetQAM256(struct drxk_state *state)
status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -5232,10 +5244,10 @@ error:
* \param channel: pointer to channel data.
* \return DRXStatus_t.
*/
-static int QAMResetQAM(struct drxk_state *state)
+static int qam_reset_qam(struct drxk_state *state)
{
int status;
- u16 cmdResult;
+ u16 cmd_result;
dprintk(1, "\n");
/* Stop QAM comstate->m_exec */
@@ -5243,10 +5255,12 @@ static int QAMResetQAM(struct drxk_state *state)
if (status < 0)
goto error;
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+ 0, NULL, 1, &cmd_result);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -5258,18 +5272,18 @@ error:
* \param channel: pointer to channel data.
* \return DRXStatus_t.
*/
-static int QAMSetSymbolrate(struct drxk_state *state)
+static int qam_set_symbolrate(struct drxk_state *state)
{
- u32 adcFrequency = 0;
- u32 symbFreq = 0;
- u32 iqmRcRate = 0;
+ u32 adc_frequency = 0;
+ u32 symb_freq = 0;
+ u32 iqm_rc_rate = 0;
u16 ratesel = 0;
- u32 lcSymbRate = 0;
+ u32 lc_symb_rate = 0;
int status;
dprintk(1, "\n");
/* Select & calculate correct IQM rate */
- adcFrequency = (state->m_sysClockFreq * 1000) / 3;
+ adc_frequency = (state->m_sys_clock_freq * 1000) / 3;
ratesel = 0;
/* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
if (state->props.symbol_rate <= 1188750)
@@ -5285,38 +5299,38 @@ static int QAMSetSymbolrate(struct drxk_state *state)
/*
IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
*/
- symbFreq = state->props.symbol_rate * (1 << ratesel);
- if (symbFreq == 0) {
+ symb_freq = state->props.symbol_rate * (1 << ratesel);
+ if (symb_freq == 0) {
/* Divide by zero */
status = -EINVAL;
goto error;
}
- iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
- (Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
+ iqm_rc_rate = (adc_frequency / symb_freq) * (1 << 21) +
+ (Frac28a((adc_frequency % symb_freq), symb_freq) >> 7) -
(1 << 23);
- status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
+ status = write32(state, IQM_RC_RATE_OFS_LO__A, iqm_rc_rate);
if (status < 0)
goto error;
- state->m_iqmRcRate = iqmRcRate;
+ state->m_iqm_rc_rate = iqm_rc_rate;
/*
- LcSymbFreq = round (.125 * symbolrate / adcFreq * (1<<15))
+ LcSymbFreq = round (.125 * symbolrate / adc_freq * (1<<15))
*/
- symbFreq = state->props.symbol_rate;
- if (adcFrequency == 0) {
+ symb_freq = state->props.symbol_rate;
+ if (adc_frequency == 0) {
/* Divide by zero */
status = -EINVAL;
goto error;
}
- lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
- (Frac28a((symbFreq % adcFrequency), adcFrequency) >>
+ lc_symb_rate = (symb_freq / adc_frequency) * (1 << 12) +
+ (Frac28a((symb_freq % adc_frequency), adc_frequency) >>
16);
- if (lcSymbRate > 511)
- lcSymbRate = 511;
- status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
+ if (lc_symb_rate > 511)
+ lc_symb_rate = 511;
+ status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lc_symb_rate);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -5329,34 +5343,36 @@ error:
* \return DRXStatus_t.
*/
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_qam_lock_status(struct drxk_state *state, u32 *p_lock_status)
{
int status;
- u16 Result[2] = { 0, 0 };
+ u16 result[2] = { 0, 0 };
dprintk(1, "\n");
- *pLockStatus = NOT_LOCKED;
+ *p_lock_status = NOT_LOCKED;
status = scu_command(state,
SCU_RAM_COMMAND_STANDARD_QAM |
SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
- Result);
+ result);
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
- if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
+ if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
/* 0x0000 NOT LOCKED */
- } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
+ } else if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
/* 0x4000 DEMOD LOCKED */
- *pLockStatus = DEMOD_LOCK;
- } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
+ *p_lock_status = DEMOD_LOCK;
+ } else if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
/* 0x8000 DEMOD + FEC LOCKED (system lock) */
- *pLockStatus = MPEG_LOCK;
+ *p_lock_status = MPEG_LOCK;
} else {
/* 0xC000 NEVER LOCKED */
/* (system will never be able to lock to the signal) */
- /* TODO: check this, intermediate & standard specific lock states are not
- taken into account here */
- *pLockStatus = NEVER_LOCK;
+ /*
+ * TODO: check this, intermediate & standard specific lock
+ * states are not taken into account here
+ */
+ *p_lock_status = NEVER_LOCK;
}
return status;
}
@@ -5368,68 +5384,70 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
#define QAM_LOCKRANGE__M 0x10
#define QAM_LOCKRANGE_NORMAL 0x10
-static int QAMDemodulatorCommand(struct drxk_state *state,
- int numberOfParameters)
+static int qam_demodulator_command(struct drxk_state *state,
+ int number_of_parameters)
{
int status;
- u16 cmdResult;
- u16 setParamParameters[4] = { 0, 0, 0, 0 };
+ u16 cmd_result;
+ u16 set_param_parameters[4] = { 0, 0, 0, 0 };
- setParamParameters[0] = state->m_Constellation; /* modulation */
- setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
+ set_param_parameters[0] = state->m_constellation; /* modulation */
+ set_param_parameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
- if (numberOfParameters == 2) {
- u16 setEnvParameters[1] = { 0 };
+ if (number_of_parameters == 2) {
+ u16 set_env_parameters[1] = { 0 };
- if (state->m_OperationMode == OM_QAM_ITU_C)
- setEnvParameters[0] = QAM_TOP_ANNEX_C;
+ if (state->m_operation_mode == OM_QAM_ITU_C)
+ set_env_parameters[0] = QAM_TOP_ANNEX_C;
else
- setEnvParameters[0] = QAM_TOP_ANNEX_A;
+ set_env_parameters[0] = QAM_TOP_ANNEX_A;
status = scu_command(state,
- SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
- 1, setEnvParameters, 1, &cmdResult);
+ SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+ 1, set_env_parameters, 1, &cmd_result);
if (status < 0)
goto error;
status = scu_command(state,
- SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
- numberOfParameters, setParamParameters,
- 1, &cmdResult);
- } else if (numberOfParameters == 4) {
- if (state->m_OperationMode == OM_QAM_ITU_C)
- setParamParameters[2] = QAM_TOP_ANNEX_C;
+ SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+ number_of_parameters, set_param_parameters,
+ 1, &cmd_result);
+ } else if (number_of_parameters == 4) {
+ if (state->m_operation_mode == OM_QAM_ITU_C)
+ set_param_parameters[2] = QAM_TOP_ANNEX_C;
else
- setParamParameters[2] = QAM_TOP_ANNEX_A;
+ set_param_parameters[2] = QAM_TOP_ANNEX_A;
- setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+ set_param_parameters[3] |= (QAM_MIRROR_AUTO_ON);
/* Env parameters */
/* check for LOCKRANGE Extented */
- /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+ /* set_param_parameters[3] |= QAM_LOCKRANGE_NORMAL; */
status = scu_command(state,
- SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
- numberOfParameters, setParamParameters,
- 1, &cmdResult);
+ SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+ number_of_parameters, set_param_parameters,
+ 1, &cmd_result);
} else {
- printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
- "count %d\n", numberOfParameters);
+ pr_warn("Unknown QAM demodulator parameter count %d\n",
+ number_of_parameters);
status = -EINVAL;
}
error:
if (status < 0)
- printk(KERN_WARNING "drxk: Warning %d on %s\n",
- status, __func__);
+ pr_warn("Warning %d on %s\n", status, __func__);
return status;
}
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
- s32 tunerFreqOffset)
+static int set_qam(struct drxk_state *state, u16 intermediate_freqk_hz,
+ s32 tuner_freq_offset)
{
int status;
- u16 cmdResult;
- int qamDemodParamCount = state->qam_demod_parameter_count;
+ u16 cmd_result;
+ int qam_demod_param_count = state->qam_demod_parameter_count;
dprintk(1, "\n");
/*
@@ -5444,7 +5462,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
if (status < 0)
goto error;
- status = QAMResetQAM(state);
+ status = qam_reset_qam(state);
if (status < 0)
goto error;
@@ -5453,27 +5471,27 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
* -set params; resets IQM,QAM,FEC HW; initializes some
* SCU variables
*/
- status = QAMSetSymbolrate(state);
+ status = qam_set_symbolrate(state);
if (status < 0)
goto error;
/* Set params */
switch (state->props.modulation) {
case QAM_256:
- state->m_Constellation = DRX_CONSTELLATION_QAM256;
+ state->m_constellation = DRX_CONSTELLATION_QAM256;
break;
case QAM_AUTO:
case QAM_64:
- state->m_Constellation = DRX_CONSTELLATION_QAM64;
+ state->m_constellation = DRX_CONSTELLATION_QAM64;
break;
case QAM_16:
- state->m_Constellation = DRX_CONSTELLATION_QAM16;
+ state->m_constellation = DRX_CONSTELLATION_QAM16;
break;
case QAM_32:
- state->m_Constellation = DRX_CONSTELLATION_QAM32;
+ state->m_constellation = DRX_CONSTELLATION_QAM32;
break;
case QAM_128:
- state->m_Constellation = DRX_CONSTELLATION_QAM128;
+ state->m_constellation = DRX_CONSTELLATION_QAM128;
break;
default:
status = -EINVAL;
@@ -5486,8 +5504,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
* the correct command. */
if (state->qam_demod_parameter_count == 4
|| !state->qam_demod_parameter_count) {
- qamDemodParamCount = 4;
- status = QAMDemodulatorCommand(state, qamDemodParamCount);
+ qam_demod_param_count = 4;
+ status = qam_demodulator_command(state, qam_demod_param_count);
}
/* Use the 2-parameter command if it was requested or if we're
@@ -5495,27 +5513,27 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
* failed. */
if (state->qam_demod_parameter_count == 2
|| (!state->qam_demod_parameter_count && status < 0)) {
- qamDemodParamCount = 2;
- status = QAMDemodulatorCommand(state, qamDemodParamCount);
+ qam_demod_param_count = 2;
+ status = qam_demodulator_command(state, qam_demod_param_count);
}
if (status < 0) {
- dprintk(1, "Could not set demodulator parameters. Make "
- "sure qam_demod_parameter_count (%d) is correct for "
- "your firmware (%s).\n",
+ dprintk(1, "Could not set demodulator parameters.\n");
+ dprintk(1,
+ "Make sure qam_demod_parameter_count (%d) is correct for your firmware (%s).\n",
state->qam_demod_parameter_count,
state->microcode_name);
goto error;
} else if (!state->qam_demod_parameter_count) {
- dprintk(1, "Auto-probing the correct QAM demodulator command "
- "parameters was successful - using %d parameters.\n",
- qamDemodParamCount);
+ dprintk(1,
+ "Auto-probing the QAM command parameters was successful - using %d parameters.\n",
+ qam_demod_param_count);
/*
* One of our commands was successful. We don't need to
* auto-probe anymore, now that we got the correct command.
*/
- state->qam_demod_parameter_count = qamDemodParamCount;
+ state->qam_demod_parameter_count = qam_demod_param_count;
}
/*
@@ -5523,16 +5541,18 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
* signal setup modulation independent registers
*/
#if 0
- status = SetFrequency(channel, tunerFreqOffset));
+ status = set_frequency(channel, tuner_freq_offset));
if (status < 0)
goto error;
#endif
- status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+ status = set_frequency_shifter(state, intermediate_freqk_hz,
+ tuner_freq_offset, true);
if (status < 0)
goto error;
/* Setup BER measurement */
- status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
+ status = set_qam_measurement(state, state->m_constellation,
+ state->props.symbol_rate);
if (status < 0)
goto error;
@@ -5605,7 +5625,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
/* Mirroring, QAM-block starting point not inverted */
- status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
+ status = write16(state, QAM_SY_SP_INV__A,
+ QAM_SY_SP_INV_SPECTRUM_INV_DIS);
if (status < 0)
goto error;
@@ -5617,20 +5638,20 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
/* STEP 4: modulation specific setup */
switch (state->props.modulation) {
case QAM_16:
- status = SetQAM16(state);
+ status = set_qam16(state);
break;
case QAM_32:
- status = SetQAM32(state);
+ status = set_qam32(state);
break;
case QAM_AUTO:
case QAM_64:
- status = SetQAM64(state);
+ status = set_qam64(state);
break;
case QAM_128:
- status = SetQAM128(state);
+ status = set_qam128(state);
break;
case QAM_256:
- status = SetQAM256(state);
+ status = set_qam256(state);
break;
default:
status = -EINVAL;
@@ -5647,12 +5668,12 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
/* Re-configure MPEG output, requires knowledge of channel bitrate */
/* extAttr->currentChannel.modulation = channel->modulation; */
/* extAttr->currentChannel.symbolrate = channel->symbolrate; */
- status = MPEGTSDtoSetup(state, state->m_OperationMode);
+ status = mpegts_dto_setup(state, state->m_operation_mode);
if (status < 0)
goto error;
- /* Start processes */
- status = MPEGTSStart(state);
+ /* start processes */
+ status = mpegts_start(state);
if (status < 0)
goto error;
status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
@@ -5666,7 +5687,9 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
/* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
- status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+ | SCU_RAM_COMMAND_CMD_DEMOD_START,
+ 0, NULL, 1, &cmd_result);
if (status < 0)
goto error;
@@ -5675,12 +5698,12 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SetQAMStandard(struct drxk_state *state,
- enum OperationMode oMode)
+static int set_qam_standard(struct drxk_state *state,
+ enum operation_mode o_mode)
{
int status;
#ifdef DRXK_QAM_TAPS
@@ -5692,14 +5715,14 @@ static int SetQAMStandard(struct drxk_state *state,
dprintk(1, "\n");
/* added antenna switch */
- SwitchAntennaToQAM(state);
+ switch_antenna_to_qam(state);
/* Ensure correct power-up mode */
- status = PowerUpQAM(state);
+ status = power_up_qam(state);
if (status < 0)
goto error;
/* Reset QAM block */
- status = QAMResetQAM(state);
+ status = qam_reset_qam(state);
if (status < 0)
goto error;
@@ -5714,15 +5737,24 @@ static int SetQAMStandard(struct drxk_state *state,
/* Upload IQM Channel Filter settings by
boot loader from ROM table */
- switch (oMode) {
+ switch (o_mode) {
case OM_QAM_ITU_A:
- status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+ status = bl_chain_cmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A,
+ DRXK_BLCC_NR_ELEMENTS_TAPS,
+ DRXK_BLC_TIMEOUT);
break;
case OM_QAM_ITU_C:
- status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+ status = bl_direct_cmd(state, IQM_CF_TAP_RE0__A,
+ DRXK_BL_ROM_OFFSET_TAPS_ITU_C,
+ DRXK_BLDC_NR_ELEMENTS_TAPS,
+ DRXK_BLC_TIMEOUT);
if (status < 0)
goto error;
- status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+ status = bl_direct_cmd(state,
+ IQM_CF_TAP_IM0__A,
+ DRXK_BL_ROM_OFFSET_TAPS_ITU_C,
+ DRXK_BLDC_NR_ELEMENTS_TAPS,
+ DRXK_BLC_TIMEOUT);
break;
default:
status = -EINVAL;
@@ -5730,13 +5762,14 @@ static int SetQAMStandard(struct drxk_state *state,
if (status < 0)
goto error;
- status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
+ status = write16(state, IQM_CF_OUT_ENA__A, 1 << IQM_CF_OUT_ENA_QAM__B);
if (status < 0)
goto error;
status = write16(state, IQM_CF_SYMMETRIC__A, 0);
if (status < 0)
goto error;
- status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
+ status = write16(state, IQM_CF_MIDTAP__A,
+ ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
if (status < 0)
goto error;
@@ -5793,7 +5826,7 @@ static int SetQAMStandard(struct drxk_state *state,
goto error;
/* turn on IQMAF. Must be done before setAgc**() */
- status = SetIqmAf(state, true);
+ status = set_iqm_af(state, true);
if (status < 0)
goto error;
status = write16(state, IQM_AF_START_LOCK__A, 0x01);
@@ -5801,7 +5834,7 @@ static int SetQAMStandard(struct drxk_state *state,
goto error;
/* IQM will not be reset from here, sync ADC and update/init AGC */
- status = ADCSynchronization(state);
+ status = adc_synchronization(state);
if (status < 0)
goto error;
@@ -5818,18 +5851,18 @@ static int SetQAMStandard(struct drxk_state *state,
/* No more resets of the IQM, current standard correctly set =>
now AGCs can be configured. */
- status = InitAGC(state, true);
+ status = init_agc(state, true);
if (status < 0)
goto error;
- status = SetPreSaw(state, &(state->m_qamPreSawCfg));
+ status = set_pre_saw(state, &(state->m_qam_pre_saw_cfg));
if (status < 0)
goto error;
/* Configure AGC's */
- status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
+ status = set_agc_rf(state, &(state->m_qam_rf_agc_cfg), true);
if (status < 0)
goto error;
- status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
+ status = set_agc_if(state, &(state->m_qam_if_agc_cfg), true);
if (status < 0)
goto error;
@@ -5837,18 +5870,19 @@ static int SetQAMStandard(struct drxk_state *state,
status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int WriteGPIO(struct drxk_state *state)
+static int write_gpio(struct drxk_state *state)
{
int status;
u16 value = 0;
dprintk(1, "\n");
/* stop lock indicator process */
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
@@ -5857,10 +5891,11 @@ static int WriteGPIO(struct drxk_state *state)
if (status < 0)
goto error;
- if (state->m_hasSAWSW) {
- if (state->UIO_mask & 0x0001) { /* UIO-1 */
+ if (state->m_has_sawsw) {
+ if (state->uio_mask & 0x0001) { /* UIO-1 */
/* write to io pad configuration register - output mode */
- status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+ status = write16(state, SIO_PDR_SMA_TX_CFG__A,
+ state->m_gpio_cfg);
if (status < 0)
goto error;
@@ -5868,7 +5903,7 @@ static int WriteGPIO(struct drxk_state *state)
status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
if (status < 0)
goto error;
- if ((state->m_GPIO & 0x0001) == 0)
+ if ((state->m_gpio & 0x0001) == 0)
value &= 0x7FFF; /* write zero to 15th bit - 1st UIO */
else
value |= 0x8000; /* write one to 15th bit - 1st UIO */
@@ -5877,9 +5912,10 @@ static int WriteGPIO(struct drxk_state *state)
if (status < 0)
goto error;
}
- if (state->UIO_mask & 0x0002) { /* UIO-2 */
+ if (state->uio_mask & 0x0002) { /* UIO-2 */
/* write to io pad configuration register - output mode */
- status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
+ status = write16(state, SIO_PDR_SMA_RX_CFG__A,
+ state->m_gpio_cfg);
if (status < 0)
goto error;
@@ -5887,7 +5923,7 @@ static int WriteGPIO(struct drxk_state *state)
status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
if (status < 0)
goto error;
- if ((state->m_GPIO & 0x0002) == 0)
+ if ((state->m_gpio & 0x0002) == 0)
value &= 0xBFFF; /* write zero to 14th bit - 2st UIO */
else
value |= 0x4000; /* write one to 14th bit - 2st UIO */
@@ -5896,9 +5932,10 @@ static int WriteGPIO(struct drxk_state *state)
if (status < 0)
goto error;
}
- if (state->UIO_mask & 0x0004) { /* UIO-3 */
+ if (state->uio_mask & 0x0004) { /* UIO-3 */
/* write to io pad configuration register - output mode */
- status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
+ status = write16(state, SIO_PDR_GPIO_CFG__A,
+ state->m_gpio_cfg);
if (status < 0)
goto error;
@@ -5906,7 +5943,7 @@ static int WriteGPIO(struct drxk_state *state)
status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
if (status < 0)
goto error;
- if ((state->m_GPIO & 0x0004) == 0)
+ if ((state->m_gpio & 0x0004) == 0)
value &= 0xFFFB; /* write zero to 2nd bit - 3rd UIO */
else
value |= 0x0004; /* write one to 2nd bit - 3rd UIO */
@@ -5920,11 +5957,11 @@ static int WriteGPIO(struct drxk_state *state)
status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SwitchAntennaToQAM(struct drxk_state *state)
+static int switch_antenna_to_qam(struct drxk_state *state)
{
int status = 0;
bool gpio_state;
@@ -5934,22 +5971,22 @@ static int SwitchAntennaToQAM(struct drxk_state *state)
if (!state->antenna_gpio)
return 0;
- gpio_state = state->m_GPIO & state->antenna_gpio;
+ gpio_state = state->m_gpio & state->antenna_gpio;
if (state->antenna_dvbt ^ gpio_state) {
/* Antenna is on DVB-T mode. Switch */
if (state->antenna_dvbt)
- state->m_GPIO &= ~state->antenna_gpio;
+ state->m_gpio &= ~state->antenna_gpio;
else
- state->m_GPIO |= state->antenna_gpio;
- status = WriteGPIO(state);
+ state->m_gpio |= state->antenna_gpio;
+ status = write_gpio(state);
}
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int SwitchAntennaToDVBT(struct drxk_state *state)
+static int switch_antenna_to_dvbt(struct drxk_state *state)
{
int status = 0;
bool gpio_state;
@@ -5959,23 +5996,23 @@ static int SwitchAntennaToDVBT(struct drxk_state *state)
if (!state->antenna_gpio)
return 0;
- gpio_state = state->m_GPIO & state->antenna_gpio;
+ gpio_state = state->m_gpio & state->antenna_gpio;
if (!(state->antenna_dvbt ^ gpio_state)) {
/* Antenna is on DVB-C mode. Switch */
if (state->antenna_dvbt)
- state->m_GPIO |= state->antenna_gpio;
+ state->m_gpio |= state->antenna_gpio;
else
- state->m_GPIO &= ~state->antenna_gpio;
- status = WriteGPIO(state);
+ state->m_gpio &= ~state->antenna_gpio;
+ status = write_gpio(state);
}
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
-static int PowerDownDevice(struct drxk_state *state)
+static int power_down_device(struct drxk_state *state)
{
/* Power down to requested mode */
/* Backup some register settings */
@@ -5986,28 +6023,29 @@ static int PowerDownDevice(struct drxk_state *state)
int status;
dprintk(1, "\n");
- if (state->m_bPDownOpenBridge) {
+ if (state->m_b_p_down_open_bridge) {
/* Open I2C bridge before power down of DRXK */
status = ConfigureI2CBridge(state, true);
if (status < 0)
goto error;
}
/* driver 0.9.0 */
- status = DVBTEnableOFDMTokenRing(state, false);
+ status = dvbt_enable_ofdm_token_ring(state, false);
if (status < 0)
goto error;
- status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
+ status = write16(state, SIO_CC_PWD_MODE__A,
+ SIO_CC_PWD_MODE_LEVEL_CLOCK);
if (status < 0)
goto error;
status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
if (status < 0)
goto error;
- state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
- status = HI_CfgCommand(state);
+ state->m_hi_cfg_ctrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+ status = hi_cfg_command(state);
error:
if (status < 0)
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
return status;
}
@@ -6015,50 +6053,56 @@ error:
static int init_drxk(struct drxk_state *state)
{
int status = 0, n = 0;
- enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
- u16 driverVersion;
+ enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
+ u16 driver_version;
dprintk(1, "\n");
- if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+ if ((state->m_drxk_state == DRXK_UNINITIALIZED)) {
drxk_i2c_lock(state);
- status = PowerUpDevice(state);
+ status = power_up_device(state);
if (status < 0)
goto error;
- status = DRXX_Open(state);
+ status = drxx_open(state);
if (status < 0)
goto error;
/* Soft reset of OFDM-, sys- and osc-clockdomain */
- status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
+ status = write16(state, SIO_CC_SOFT_RST__A,
+ SIO_CC_SOFT_RST_OFDM__M
+ | SIO_CC_SOFT_RST_SYS__M
+ | SIO_CC_SOFT_RST_OSC__M);
if (status < 0)
goto error;
status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
if (status < 0)
goto error;
- /* TODO is this needed, if yes how much delay in worst case scenario */
- msleep(1);
- state->m_DRXK_A3_PATCH_CODE = true;
- status = GetDeviceCapabilities(state);
+ /*
+ * TODO is this needed? If yes, how much delay in
+ * worst case scenario
+ */
+ usleep_range(1000, 2000);
+ state->m_drxk_a3_patch_code = true;
+ status = get_device_capabilities(state);
if (status < 0)
goto error;
/* Bridge delay, uses oscilator clock */
/* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
/* SDA brdige delay */
- state->m_HICfgBridgeDelay =
- (u16) ((state->m_oscClockFreq / 1000) *
+ state->m_hi_cfg_bridge_delay =
+ (u16) ((state->m_osc_clock_freq / 1000) *
HI_I2C_BRIDGE_DELAY) / 1000;
/* Clipping */
- if (state->m_HICfgBridgeDelay >
+ if (state->m_hi_cfg_bridge_delay >
SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
- state->m_HICfgBridgeDelay =
+ state->m_hi_cfg_bridge_delay =
SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
}
/* SCL bridge delay, same as SDA for now */
- state->m_HICfgBridgeDelay +=
- state->m_HICfgBridgeDelay <<
+ state->m_hi_cfg_bridge_delay +=
+ state->m_hi_cfg_bridge_delay <<
SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
- status = InitHI(state);
+ status = init_hi(state);
if (status < 0)
goto error;
/* disable various processes */
@@ -6067,13 +6111,14 @@ static int init_drxk(struct drxk_state *state)
&& !(state->m_DRXK_A2_ROM_CODE))
#endif
{
- status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+ status = write16(state, SCU_RAM_GPIO__A,
+ SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
if (status < 0)
goto error;
}
/* disable MPEG port */
- status = MPEGTSDisable(state);
+ status = mpegts_disable(state);
if (status < 0)
goto error;
@@ -6086,27 +6131,30 @@ static int init_drxk(struct drxk_state *state)
goto error;
/* enable token-ring bus through OFDM block for possible ucode upload */
- status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
+ status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A,
+ SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
if (status < 0)
goto error;
/* include boot loader section */
- status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
+ status = write16(state, SIO_BL_COMM_EXEC__A,
+ SIO_BL_COMM_EXEC_ACTIVE);
if (status < 0)
goto error;
- status = BLChainCmd(state, 0, 6, 100);
+ status = bl_chain_cmd(state, 0, 6, 100);
if (status < 0)
goto error;
if (state->fw) {
- status = DownloadMicrocode(state, state->fw->data,
+ status = download_microcode(state, state->fw->data,
state->fw->size);
if (status < 0)
goto error;
}
/* disable token-ring bus through OFDM block for possible ucode upload */
- status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
+ status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A,
+ SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
if (status < 0)
goto error;
@@ -6114,14 +6162,14 @@ static int init_drxk(struct drxk_state *state)
status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
if (status < 0)
goto error;
- status = DRXX_Open(state);
+ status = drxx_open(state);
if (status < 0)
goto error;
/* added for test */
msleep(30);
- powerMode = DRXK_POWER_DOWN_OFDM;
- status = CtrlPowerMode(state, &powerMode);
+ power_mode = DRXK_POWER_DOWN_OFDM;
+ status = ctrl_power_mode(state, &power_mode);
if (status < 0)
goto error;
@@ -6131,33 +6179,38 @@ static int init_drxk(struct drxk_state *state)
Not using SCU command interface for SCU register access since no
microcode may be present.
*/
- driverVersion =
+ driver_version =
(((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
(((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
((DRXK_VERSION_MAJOR % 10) << 4) +
(DRXK_VERSION_MINOR % 10);
- status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
+ status = write16(state, SCU_RAM_DRIVER_VER_HI__A,
+ driver_version);
if (status < 0)
goto error;
- driverVersion =
+ driver_version =
(((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
(((DRXK_VERSION_PATCH / 100) % 10) << 8) +
(((DRXK_VERSION_PATCH / 10) % 10) << 4) +
(DRXK_VERSION_PATCH % 10);
- status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
+ status = write16(state, SCU_RAM_DRIVER_VER_LO__A,
+ driver_version);
if (status < 0)
goto error;
- printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
+ pr_info("DRXK driver version %d.%d.%d\n",
DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
DRXK_VERSION_PATCH);
- /* Dirty fix of default values for ROM/PATCH microcode
- Dirty because this fix makes it impossible to setup suitable values
- before calling DRX_Open. This solution requires changes to RF AGC speed
- to be done via the CTRL function after calling DRX_Open */
+ /*
+ * Dirty fix of default values for ROM/PATCH microcode
+ * Dirty because this fix makes it impossible to setup
+ * suitable values before calling DRX_Open. This solution
+ * requires changes to RF AGC speed to be done via the CTRL
+ * function after calling DRX_Open
+ */
- /* m_dvbtRfAgcCfg.speed = 3; */
+ /* m_dvbt_rf_agc_cfg.speed = 3; */
/* Reset driver debug flags to 0 */
status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
@@ -6170,42 +6223,42 @@ static int init_drxk(struct drxk_state *state)
if (status < 0)
goto error;
/* MPEGTS functions are still the same */
- status = MPEGTSDtoInit(state);
+ status = mpegts_dto_init(state);
if (status < 0)
goto error;
- status = MPEGTSStop(state);
+ status = mpegts_stop(state);
if (status < 0)
goto error;
- status = MPEGTSConfigurePolarity(state);
+ status = mpegts_configure_polarity(state);
if (status < 0)
goto error;
- status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
+ status = mpegts_configure_pins(state, state->m_enable_mpeg_output);
if (status < 0)
goto error;
/* added: configure GPIO */
- status = WriteGPIO(state);
+ status = write_gpio(state);
if (status < 0)
goto error;
- state->m_DrxkState = DRXK_STOPPED;
+ state->m_drxk_state = DRXK_STOPPED;
- if (state->m_bPowerDown) {
- status = PowerDownDevice(state);
+ if (state->m_b_power_down) {
+ status = power_down_device(state);
if (status < 0)
goto error;
- state->m_DrxkState = DRXK_POWERED_DOWN;
+ state->m_drxk_state = DRXK_POWERED_DOWN;
} else
- state->m_DrxkState = DRXK_STOPPED;
+ state->m_drxk_state = DRXK_STOPPED;
/* Initialize the supported delivery systems */
n = 0;
- if (state->m_hasDVBC) {
+ if (state->m_has_dvbc) {
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
strlcat(state->frontend.ops.info.name, " DVB-C",
sizeof(state->frontend.ops.info.name));
}
- if (state->m_hasDVBT) {
+ if (state->m_has_dvbt) {
state->frontend.ops.delsys[n++] = SYS_DVBT;
strlcat(state->frontend.ops.info.name, " DVB-T",
sizeof(state->frontend.ops.info.name));
@@ -6214,9 +6267,9 @@ static int init_drxk(struct drxk_state *state)
}
error:
if (status < 0) {
- state->m_DrxkState = DRXK_NO_DEV;
+ state->m_drxk_state = DRXK_NO_DEV;
drxk_i2c_unlock(state);
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ pr_err("Error %d on %s\n", status, __func__);
}
return status;
@@ -6229,11 +6282,9 @@ static void load_firmware_cb(const struct firmware *fw,
dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
if (!fw) {
- printk(KERN_ERR
- "drxk: Could not load firmware file %s.\n",
+ pr_err("Could not load firmware file %s.\n",
state->microcode_name);
- printk(KERN_INFO
- "drxk: Copy %s to your hotplug directory!\n",
+ pr_info("Copy %s to your hotplug directory!\n",
state->microcode_name);
state->microcode_name = NULL;
@@ -6270,12 +6321,12 @@ static int drxk_sleep(struct dvb_frontend *fe)
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return 0;
- ShutDown(state);
+ shut_down(state);
return 0;
}
@@ -6285,7 +6336,7 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
dprintk(1, ": %s\n", enable ? "enable" : "disable");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
return ConfigureI2CBridge(state, enable ? true : false);
@@ -6300,15 +6351,14 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
if (!fe->ops.tuner_ops.get_if_frequency) {
- printk(KERN_ERR
- "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
+ pr_err("Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
return -EINVAL;
}
@@ -6323,22 +6373,23 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
state->props = *p;
if (old_delsys != delsys) {
- ShutDown(state);
+ shut_down(state);
switch (delsys) {
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_C:
- if (!state->m_hasDVBC)
+ if (!state->m_has_dvbc)
return -EINVAL;
- state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
+ state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ?
+ true : false;
if (state->m_itut_annex_c)
- SetOperationMode(state, OM_QAM_ITU_C);
+ setoperation_mode(state, OM_QAM_ITU_C);
else
- SetOperationMode(state, OM_QAM_ITU_A);
+ setoperation_mode(state, OM_QAM_ITU_A);
break;
case SYS_DVBT:
- if (!state->m_hasDVBT)
+ if (!state->m_has_dvbt)
return -EINVAL;
- SetOperationMode(state, OM_DVBT);
+ setoperation_mode(state, OM_DVBT);
break;
default:
return -EINVAL;
@@ -6346,7 +6397,7 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
}
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
- Start(state, 0, IF);
+ start(state, 0, IF);
/* After set_frontend, stats aren't avaliable */
p->strength.stat[0].scale = FE_SCALE_RELATIVE;
@@ -6366,31 +6417,31 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
static int get_strength(struct drxk_state *state, u64 *strength)
{
int status;
- struct SCfgAgc rfAgc, ifAgc;
- u32 totalGain = 0;
+ struct s_cfg_agc rf_agc, if_agc;
+ u32 total_gain = 0;
u32 atten = 0;
- u32 agcRange = 0;
+ u32 agc_range = 0;
u16 scu_lvl = 0;
u16 scu_coc = 0;
/* FIXME: those are part of the tuner presets */
- u16 tunerRfGain = 50; /* Default value on az6007 driver */
- u16 tunerIfGain = 40; /* Default value on az6007 driver */
+ u16 tuner_rf_gain = 50; /* Default value on az6007 driver */
+ u16 tuner_if_gain = 40; /* Default value on az6007 driver */
*strength = 0;
- if (IsDVBT(state)) {
- rfAgc = state->m_dvbtRfAgcCfg;
- ifAgc = state->m_dvbtIfAgcCfg;
- } else if (IsQAM(state)) {
- rfAgc = state->m_qamRfAgcCfg;
- ifAgc = state->m_qamIfAgcCfg;
+ if (is_dvbt(state)) {
+ rf_agc = state->m_dvbt_rf_agc_cfg;
+ if_agc = state->m_dvbt_if_agc_cfg;
+ } else if (is_qam(state)) {
+ rf_agc = state->m_qam_rf_agc_cfg;
+ if_agc = state->m_qam_if_agc_cfg;
} else {
- rfAgc = state->m_atvRfAgcCfg;
- ifAgc = state->m_atvIfAgcCfg;
+ rf_agc = state->m_atv_rf_agc_cfg;
+ if_agc = state->m_atv_if_agc_cfg;
}
- if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
- /* SCU outputLevel */
+ if (rf_agc.ctrl_mode == DRXK_AGC_CTRL_AUTO) {
+ /* SCU output_level */
status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl);
if (status < 0)
return status;
@@ -6401,54 +6452,54 @@ static int get_strength(struct drxk_state *state, u64 *strength)
return status;
if (((u32) scu_lvl + (u32) scu_coc) < 0xffff)
- rfAgc.outputLevel = scu_lvl + scu_coc;
+ rf_agc.output_level = scu_lvl + scu_coc;
else
- rfAgc.outputLevel = 0xffff;
+ rf_agc.output_level = 0xffff;
/* Take RF gain into account */
- totalGain += tunerRfGain;
+ total_gain += tuner_rf_gain;
/* clip output value */
- if (rfAgc.outputLevel < rfAgc.minOutputLevel)
- rfAgc.outputLevel = rfAgc.minOutputLevel;
- if (rfAgc.outputLevel > rfAgc.maxOutputLevel)
- rfAgc.outputLevel = rfAgc.maxOutputLevel;
+ if (rf_agc.output_level < rf_agc.min_output_level)
+ rf_agc.output_level = rf_agc.min_output_level;
+ if (rf_agc.output_level > rf_agc.max_output_level)
+ rf_agc.output_level = rf_agc.max_output_level;
- agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel);
- if (agcRange > 0) {
+ agc_range = (u32) (rf_agc.max_output_level - rf_agc.min_output_level);
+ if (agc_range > 0) {
atten += 100UL *
- ((u32)(tunerRfGain)) *
- ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel))
- / agcRange;
+ ((u32)(tuner_rf_gain)) *
+ ((u32)(rf_agc.output_level - rf_agc.min_output_level))
+ / agc_range;
}
}
- if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+ if (if_agc.ctrl_mode == DRXK_AGC_CTRL_AUTO) {
status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A,
- &ifAgc.outputLevel);
+ &if_agc.output_level);
if (status < 0)
return status;
status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A,
- &ifAgc.top);
+ &if_agc.top);
if (status < 0)
return status;
/* Take IF gain into account */
- totalGain += (u32) tunerIfGain;
+ total_gain += (u32) tuner_if_gain;
/* clip output value */
- if (ifAgc.outputLevel < ifAgc.minOutputLevel)
- ifAgc.outputLevel = ifAgc.minOutputLevel;
- if (ifAgc.outputLevel > ifAgc.maxOutputLevel)
- ifAgc.outputLevel = ifAgc.maxOutputLevel;
+ if (if_agc.output_level < if_agc.min_output_level)
+ if_agc.output_level = if_agc.min_output_level;
+ if (if_agc.output_level > if_agc.max_output_level)
+ if_agc.output_level = if_agc.max_output_level;
- agcRange = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel);
- if (agcRange > 0) {
+ agc_range = (u32)(if_agc.max_output_level - if_agc.min_output_level);
+ if (agc_range > 0) {
atten += 100UL *
- ((u32)(tunerIfGain)) *
- ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel))
- / agcRange;
+ ((u32)(tuner_if_gain)) *
+ ((u32)(if_agc.output_level - if_agc.min_output_level))
+ / agc_range;
}
}
@@ -6456,8 +6507,8 @@ static int get_strength(struct drxk_state *state, u64 *strength)
* Convert to 0..65535 scale.
* If it can't be measured (AGC is disabled), just show 100%.
*/
- if (totalGain > 0)
- *strength = (65535UL * atten / totalGain / 100);
+ if (total_gain > 0)
+ *strength = (65535UL * atten / total_gain / 100);
else
*strength = 65535;
@@ -6480,14 +6531,14 @@ static int drxk_get_stats(struct dvb_frontend *fe)
u32 pkt_error_count;
s32 cnr;
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
/* get status */
state->fe_status = 0;
- GetLockStatus(state, &stat);
+ get_lock_status(state, &stat);
if (stat == MPEG_LOCK)
state->fe_status |= 0x1f;
if (stat == FEC_LOCK)
@@ -6503,7 +6554,7 @@ static int drxk_get_stats(struct dvb_frontend *fe)
if (stat >= DEMOD_LOCK) {
- GetSignalToNoise(state, &cnr);
+ get_signal_to_noise(state, &cnr);
c->cnr.stat[0].svalue = cnr * 100;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
} else {
@@ -6524,9 +6575,11 @@ static int drxk_get_stats(struct dvb_frontend *fe)
/* BER measurement is valid if at least FEC lock is achieved */
- /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written
- to set nr of symbols or bits over which
- to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */
+ /*
+ * OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be
+ * written to set nr of symbols or bits over which to measure
+ * EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg().
+ */
/* Read registers for post/preViterbi BER calculation */
status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, &reg16);
@@ -6610,9 +6663,9 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
*strength = c->strength.stat[0].uvalue;
@@ -6626,12 +6679,12 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
- GetSignalToNoise(state, &snr2);
+ get_signal_to_noise(state, &snr2);
/* No negative SNR, clip to zero */
if (snr2 < 0)
@@ -6647,27 +6700,27 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
- DVBTQAMGetAccPktErr(state, &err);
+ dvbtqam_get_acc_pkt_err(state, &err);
*ucblocks = (u32) err;
return 0;
}
-static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
- *sets)
+static int drxk_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *sets)
{
struct drxk_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
+ if (state->m_drxk_state == DRXK_NO_DEV)
return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
+ if (state->m_drxk_state == DRXK_UNINITIALIZED)
return -EAGAIN;
switch (p->delivery_system) {
@@ -6737,36 +6790,36 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
state->no_i2c_bridge = config->no_i2c_bridge;
state->antenna_gpio = config->antenna_gpio;
state->antenna_dvbt = config->antenna_dvbt;
- state->m_ChunkSize = config->chunk_size;
+ state->m_chunk_size = config->chunk_size;
state->enable_merr_cfg = config->enable_merr_cfg;
if (config->dynamic_clk) {
- state->m_DVBTStaticCLK = 0;
- state->m_DVBCStaticCLK = 0;
+ state->m_dvbt_static_clk = 0;
+ state->m_dvbc_static_clk = 0;
} else {
- state->m_DVBTStaticCLK = 1;
- state->m_DVBCStaticCLK = 1;
+ state->m_dvbt_static_clk = 1;
+ state->m_dvbc_static_clk = 1;
}
if (config->mpeg_out_clk_strength)
- state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+ state->m_ts_clockk_strength = config->mpeg_out_clk_strength & 0x07;
else
- state->m_TSClockkStrength = 0x06;
+ state->m_ts_clockk_strength = 0x06;
if (config->parallel_ts)
- state->m_enableParallel = true;
+ state->m_enable_parallel = true;
else
- state->m_enableParallel = false;
+ state->m_enable_parallel = false;
/* NOTE: as more UIO bits will be used, add them to the mask */
- state->UIO_mask = config->antenna_gpio;
+ state->uio_mask = config->antenna_gpio;
/* Default gpio to DVB-C */
if (!state->antenna_dvbt && state->antenna_gpio)
- state->m_GPIO |= state->antenna_gpio;
+ state->m_gpio |= state->antenna_gpio;
else
- state->m_GPIO &= ~state->antenna_gpio;
+ state->m_gpio &= ~state->antenna_gpio;
mutex_init(&state->mutex);
@@ -6792,8 +6845,7 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
GFP_KERNEL,
state, load_firmware_cb);
if (status < 0) {
- printk(KERN_ERR
- "drxk: failed to request a firmware\n");
+ pr_err("failed to request a firmware\n");
return NULL;
}
}
@@ -6821,11 +6873,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- printk(KERN_INFO "drxk: frontend initialized.\n");
+ pr_info("frontend initialized.\n");
return &state->frontend;
error:
- printk(KERN_ERR "drxk: not found\n");
+ pr_err("not found\n");
kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
index b8424f15f9a6..bae9c71dc3e9 100644
--- a/drivers/media/dvb-frontends/drxk_hard.h
+++ b/drivers/media/dvb-frontends/drxk_hard.h
@@ -46,7 +46,7 @@
#define IQM_RC_ADJ_SEL_B_QAM 0x1
#define IQM_RC_ADJ_SEL_B_VSB 0x2
-enum OperationMode {
+enum operation_mode {
OM_NONE,
OM_QAM_ITU_A,
OM_QAM_ITU_B,
@@ -54,7 +54,7 @@ enum OperationMode {
OM_DVBT
};
-enum DRXPowerMode {
+enum drx_power_mode {
DRX_POWER_UP = 0,
DRX_POWER_MODE_1,
DRX_POWER_MODE_2,
@@ -77,24 +77,29 @@ enum DRXPowerMode {
};
-/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
+/* Intermediate power mode for DRXK, power down OFDM clock domain */
#ifndef DRXK_POWER_DOWN_OFDM
#define DRXK_POWER_DOWN_OFDM DRX_POWER_MODE_1
#endif
-/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
+/* Intermediate power mode for DRXK, power down core (sysclk) */
#ifndef DRXK_POWER_DOWN_CORE
#define DRXK_POWER_DOWN_CORE DRX_POWER_MODE_9
#endif
-/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
+/* Intermediate power mode for DRXK, power down pll (only osc runs) */
#ifndef DRXK_POWER_DOWN_PLL
#define DRXK_POWER_DOWN_PLL DRX_POWER_MODE_10
#endif
-enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
-enum EDrxkState {
+enum agc_ctrl_mode {
+ DRXK_AGC_CTRL_AUTO = 0,
+ DRXK_AGC_CTRL_USER,
+ DRXK_AGC_CTRL_OFF
+};
+
+enum e_drxk_state {
DRXK_UNINITIALIZED = 0,
DRXK_STOPPED,
DRXK_DTV_STARTED,
@@ -103,7 +108,7 @@ enum EDrxkState {
DRXK_NO_DEV /* If drxk init failed */
};
-enum EDrxkCoefArrayIndex {
+enum e_drxk_coef_array_index {
DRXK_COEF_IDX_MN = 0,
DRXK_COEF_IDX_FM ,
DRXK_COEF_IDX_L ,
@@ -113,13 +118,13 @@ enum EDrxkCoefArrayIndex {
DRXK_COEF_IDX_I ,
DRXK_COEF_IDX_MAX
};
-enum EDrxkSifAttenuation {
+enum e_drxk_sif_attenuation {
DRXK_SIF_ATTENUATION_0DB,
DRXK_SIF_ATTENUATION_3DB,
DRXK_SIF_ATTENUATION_6DB,
DRXK_SIF_ATTENUATION_9DB
};
-enum EDrxkConstellation {
+enum e_drxk_constellation {
DRX_CONSTELLATION_BPSK = 0,
DRX_CONSTELLATION_QPSK,
DRX_CONSTELLATION_PSK8,
@@ -133,7 +138,7 @@ enum EDrxkConstellation {
DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
DRX_CONSTELLATION_AUTO = DRX_AUTO
};
-enum EDrxkInterleaveMode {
+enum e_drxk_interleave_mode {
DRXK_QAM_I12_J17 = 16,
DRXK_QAM_I_UNKNOWN = DRX_UNKNOWN
};
@@ -144,14 +149,14 @@ enum {
DRXK_SPIN_UNKNOWN
};
-enum DRXKCfgDvbtSqiSpeed {
+enum drxk_cfg_dvbt_sqi_speed {
DRXK_DVBT_SQI_SPEED_FAST = 0,
DRXK_DVBT_SQI_SPEED_MEDIUM,
DRXK_DVBT_SQI_SPEED_SLOW,
DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
} ;
-enum DRXFftmode_t {
+enum drx_fftmode_t {
DRX_FFTMODE_2K = 0,
DRX_FFTMODE_4K,
DRX_FFTMODE_8K,
@@ -159,47 +164,47 @@ enum DRXFftmode_t {
DRX_FFTMODE_AUTO = DRX_AUTO
};
-enum DRXMPEGStrWidth_t {
+enum drxmpeg_str_width_t {
DRX_MPEG_STR_WIDTH_1,
DRX_MPEG_STR_WIDTH_8
};
-enum DRXQamLockRange_t {
+enum drx_qam_lock_range_t {
DRX_QAM_LOCKRANGE_NORMAL,
DRX_QAM_LOCKRANGE_EXTENDED
};
-struct DRXKCfgDvbtEchoThres_t {
+struct drxk_cfg_dvbt_echo_thres_t {
u16 threshold;
- enum DRXFftmode_t fftMode;
+ enum drx_fftmode_t fft_mode;
} ;
-struct SCfgAgc {
- enum AGC_CTRL_MODE ctrlMode; /* off, user, auto */
- u16 outputLevel; /* range dependent on AGC */
- u16 minOutputLevel; /* range dependent on AGC */
- u16 maxOutputLevel; /* range dependent on AGC */
+struct s_cfg_agc {
+ enum agc_ctrl_mode ctrl_mode; /* off, user, auto */
+ u16 output_level; /* range dependent on AGC */
+ u16 min_output_level; /* range dependent on AGC */
+ u16 max_output_level; /* range dependent on AGC */
u16 speed; /* range dependent on AGC */
u16 top; /* rf-agc take over point */
- u16 cutOffCurrent; /* rf-agc is accelerated if output current
+ u16 cut_off_current; /* rf-agc is accelerated if output current
is below cut-off current */
- u16 IngainTgtMax;
- u16 FastClipCtrlDelay;
+ u16 ingain_tgt_max;
+ u16 fast_clip_ctrl_delay;
};
-struct SCfgPreSaw {
+struct s_cfg_pre_saw {
u16 reference; /* pre SAW reference value, range 0 .. 31 */
- bool usePreSaw; /* TRUE algorithms must use pre SAW sense */
+ bool use_pre_saw; /* TRUE algorithms must use pre SAW sense */
};
-struct DRXKOfdmScCmd_t {
- u16 cmd; /**< Command number */
- u16 subcmd; /**< Sub-command parameter*/
- u16 param0; /**< General purpous param */
- u16 param1; /**< General purpous param */
- u16 param2; /**< General purpous param */
- u16 param3; /**< General purpous param */
- u16 param4; /**< General purpous param */
+struct drxk_ofdm_sc_cmd_t {
+ u16 cmd; /* Command number */
+ u16 subcmd; /* Sub-command parameter*/
+ u16 param0; /* General purpous param */
+ u16 param1; /* General purpous param */
+ u16 param2; /* General purpous param */
+ u16 param3; /* General purpous param */
+ u16 param4; /* General purpous param */
};
struct drxk_state {
@@ -213,121 +218,121 @@ struct drxk_state {
struct mutex mutex;
- u32 m_Instance; /**< Channel 1,2,3 or 4 */
-
- int m_ChunkSize;
- u8 Chunk[256];
-
- bool m_hasLNA;
- bool m_hasDVBT;
- bool m_hasDVBC;
- bool m_hasAudio;
- bool m_hasATV;
- bool m_hasOOB;
- bool m_hasSAWSW; /**< TRUE if mat_tx is available */
- bool m_hasGPIO1; /**< TRUE if mat_rx is available */
- bool m_hasGPIO2; /**< TRUE if GPIO is available */
- bool m_hasIRQN; /**< TRUE if IRQN is available */
- u16 m_oscClockFreq;
- u16 m_HICfgTimingDiv;
- u16 m_HICfgBridgeDelay;
- u16 m_HICfgWakeUpKey;
- u16 m_HICfgTimeout;
- u16 m_HICfgCtrl;
- s32 m_sysClockFreq; /**< system clock frequency in kHz */
-
- enum EDrxkState m_DrxkState; /**< State of Drxk (init,stopped,started) */
- enum OperationMode m_OperationMode; /**< digital standards */
- struct SCfgAgc m_vsbRfAgcCfg; /**< settings for VSB RF-AGC */
- struct SCfgAgc m_vsbIfAgcCfg; /**< settings for VSB IF-AGC */
- u16 m_vsbPgaCfg; /**< settings for VSB PGA */
- struct SCfgPreSaw m_vsbPreSawCfg; /**< settings for pre SAW sense */
- s32 m_Quality83percent; /**< MER level (*0.1 dB) for 83% quality indication */
- s32 m_Quality93percent; /**< MER level (*0.1 dB) for 93% quality indication */
- bool m_smartAntInverted;
- bool m_bDebugEnableBridge;
- bool m_bPDownOpenBridge; /**< only open DRXK bridge before power-down once it has been accessed */
- bool m_bPowerDown; /**< Power down when not used */
-
- u32 m_IqmFsRateOfs; /**< frequency shift as written to DRXK register (28bit fixpoint) */
-
- bool m_enableMPEGOutput; /**< If TRUE, enable MPEG output */
- bool m_insertRSByte; /**< If TRUE, insert RS byte */
- bool m_enableParallel; /**< If TRUE, parallel out otherwise serial */
- bool m_invertDATA; /**< If TRUE, invert DATA signals */
- bool m_invertERR; /**< If TRUE, invert ERR signal */
- bool m_invertSTR; /**< If TRUE, invert STR signals */
- bool m_invertVAL; /**< If TRUE, invert VAL signals */
- bool m_invertCLK; /**< If TRUE, invert CLK signals */
- bool m_DVBCStaticCLK;
- bool m_DVBTStaticCLK; /**< If TRUE, static MPEG clockrate will
+ u32 m_instance; /* Channel 1,2,3 or 4 */
+
+ int m_chunk_size;
+ u8 chunk[256];
+
+ bool m_has_lna;
+ bool m_has_dvbt;
+ bool m_has_dvbc;
+ bool m_has_audio;
+ bool m_has_atv;
+ bool m_has_oob;
+ bool m_has_sawsw; /* TRUE if mat_tx is available */
+ bool m_has_gpio1; /* TRUE if mat_rx is available */
+ bool m_has_gpio2; /* TRUE if GPIO is available */
+ bool m_has_irqn; /* TRUE if IRQN is available */
+ u16 m_osc_clock_freq;
+ u16 m_hi_cfg_timing_div;
+ u16 m_hi_cfg_bridge_delay;
+ u16 m_hi_cfg_wake_up_key;
+ u16 m_hi_cfg_timeout;
+ u16 m_hi_cfg_ctrl;
+ s32 m_sys_clock_freq; /* system clock frequency in kHz */
+
+ enum e_drxk_state m_drxk_state; /* State of Drxk (init,stopped,started) */
+ enum operation_mode m_operation_mode; /* digital standards */
+ struct s_cfg_agc m_vsb_rf_agc_cfg; /* settings for VSB RF-AGC */
+ struct s_cfg_agc m_vsb_if_agc_cfg; /* settings for VSB IF-AGC */
+ u16 m_vsb_pga_cfg; /* settings for VSB PGA */
+ struct s_cfg_pre_saw m_vsb_pre_saw_cfg; /* settings for pre SAW sense */
+ s32 m_Quality83percent; /* MER level (*0.1 dB) for 83% quality indication */
+ s32 m_Quality93percent; /* MER level (*0.1 dB) for 93% quality indication */
+ bool m_smart_ant_inverted;
+ bool m_b_debug_enable_bridge;
+ bool m_b_p_down_open_bridge; /* only open DRXK bridge before power-down once it has been accessed */
+ bool m_b_power_down; /* Power down when not used */
+
+ u32 m_iqm_fs_rate_ofs; /* frequency shift as written to DRXK register (28bit fixpoint) */
+
+ bool m_enable_mpeg_output; /* If TRUE, enable MPEG output */
+ bool m_insert_rs_byte; /* If TRUE, insert RS byte */
+ bool m_enable_parallel; /* If TRUE, parallel out otherwise serial */
+ bool m_invert_data; /* If TRUE, invert DATA signals */
+ bool m_invert_err; /* If TRUE, invert ERR signal */
+ bool m_invert_str; /* If TRUE, invert STR signals */
+ bool m_invert_val; /* If TRUE, invert VAL signals */
+ bool m_invert_clk; /* If TRUE, invert CLK signals */
+ bool m_dvbc_static_clk;
+ bool m_dvbt_static_clk; /* If TRUE, static MPEG clockrate will
be used, otherwise clockrate will
adapt to the bitrate of the TS */
- u32 m_DVBTBitrate;
- u32 m_DVBCBitrate;
+ u32 m_dvbt_bitrate;
+ u32 m_dvbc_bitrate;
- u8 m_TSDataStrength;
- u8 m_TSClockkStrength;
+ u8 m_ts_data_strength;
+ u8 m_ts_clockk_strength;
bool m_itut_annex_c; /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
- enum DRXMPEGStrWidth_t m_widthSTR; /**< MPEG start width */
- u32 m_mpegTsStaticBitrate; /**< Maximum bitrate in b/s in case
+ enum drxmpeg_str_width_t m_width_str; /* MPEG start width */
+ u32 m_mpeg_ts_static_bitrate; /* Maximum bitrate in b/s in case
static clockrate is selected */
- /* LARGE_INTEGER m_StartTime; */ /**< Contains the time of the last demod start */
- s32 m_MpegLockTimeOut; /**< WaitForLockStatus Timeout (counts from start time) */
- s32 m_DemodLockTimeOut; /**< WaitForLockStatus Timeout (counts from start time) */
-
- bool m_disableTEIhandling;
-
- bool m_RfAgcPol;
- bool m_IfAgcPol;
-
- struct SCfgAgc m_atvRfAgcCfg; /**< settings for ATV RF-AGC */
- struct SCfgAgc m_atvIfAgcCfg; /**< settings for ATV IF-AGC */
- struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
- bool m_phaseCorrectionBypass;
- s16 m_atvTopVidPeak;
- u16 m_atvTopNoiseTh;
- enum EDrxkSifAttenuation m_sifAttenuation;
- bool m_enableCVBSOutput;
- bool m_enableSIFOutput;
- bool m_bMirrorFreqSpect;
- enum EDrxkConstellation m_Constellation; /**< Constellation type of the channel */
- u32 m_CurrSymbolRate; /**< Current QAM symbol rate */
- struct SCfgAgc m_qamRfAgcCfg; /**< settings for QAM RF-AGC */
- struct SCfgAgc m_qamIfAgcCfg; /**< settings for QAM IF-AGC */
- u16 m_qamPgaCfg; /**< settings for QAM PGA */
- struct SCfgPreSaw m_qamPreSawCfg; /**< settings for QAM pre SAW sense */
- enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
- u16 m_fecRsPlen;
- u16 m_fecRsPrescale;
-
- enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
-
- u16 m_GPIO;
- u16 m_GPIOCfg;
-
- struct SCfgAgc m_dvbtRfAgcCfg; /**< settings for QAM RF-AGC */
- struct SCfgAgc m_dvbtIfAgcCfg; /**< settings for QAM IF-AGC */
- struct SCfgPreSaw m_dvbtPreSawCfg; /**< settings for QAM pre SAW sense */
-
- u16 m_agcFastClipCtrlDelay;
- bool m_adcCompPassed;
+ /* LARGE_INTEGER m_startTime; */ /* Contains the time of the last demod start */
+ s32 m_mpeg_lock_time_out; /* WaitForLockStatus Timeout (counts from start time) */
+ s32 m_demod_lock_time_out; /* WaitForLockStatus Timeout (counts from start time) */
+
+ bool m_disable_te_ihandling;
+
+ bool m_rf_agc_pol;
+ bool m_if_agc_pol;
+
+ struct s_cfg_agc m_atv_rf_agc_cfg; /* settings for ATV RF-AGC */
+ struct s_cfg_agc m_atv_if_agc_cfg; /* settings for ATV IF-AGC */
+ struct s_cfg_pre_saw m_atv_pre_saw_cfg; /* settings for ATV pre SAW sense */
+ bool m_phase_correction_bypass;
+ s16 m_atv_top_vid_peak;
+ u16 m_atv_top_noise_th;
+ enum e_drxk_sif_attenuation m_sif_attenuation;
+ bool m_enable_cvbs_output;
+ bool m_enable_sif_output;
+ bool m_b_mirror_freq_spect;
+ enum e_drxk_constellation m_constellation; /* constellation type of the channel */
+ u32 m_curr_symbol_rate; /* Current QAM symbol rate */
+ struct s_cfg_agc m_qam_rf_agc_cfg; /* settings for QAM RF-AGC */
+ struct s_cfg_agc m_qam_if_agc_cfg; /* settings for QAM IF-AGC */
+ u16 m_qam_pga_cfg; /* settings for QAM PGA */
+ struct s_cfg_pre_saw m_qam_pre_saw_cfg; /* settings for QAM pre SAW sense */
+ enum e_drxk_interleave_mode m_qam_interleave_mode; /* QAM Interleave mode */
+ u16 m_fec_rs_plen;
+ u16 m_fec_rs_prescale;
+
+ enum drxk_cfg_dvbt_sqi_speed m_sqi_speed;
+
+ u16 m_gpio;
+ u16 m_gpio_cfg;
+
+ struct s_cfg_agc m_dvbt_rf_agc_cfg; /* settings for QAM RF-AGC */
+ struct s_cfg_agc m_dvbt_if_agc_cfg; /* settings for QAM IF-AGC */
+ struct s_cfg_pre_saw m_dvbt_pre_saw_cfg; /* settings for QAM pre SAW sense */
+
+ u16 m_agcfast_clip_ctrl_delay;
+ bool m_adc_comp_passed;
u16 m_adcCompCoef[64];
- u16 m_adcState;
+ u16 m_adc_state;
u8 *m_microcode;
int m_microcode_length;
- bool m_DRXK_A3_ROM_CODE;
- bool m_DRXK_A3_PATCH_CODE;
+ bool m_drxk_a3_rom_code;
+ bool m_drxk_a3_patch_code;
bool m_rfmirror;
- u8 m_deviceSpin;
- u32 m_iqmRcRate;
+ u8 m_device_spin;
+ u32 m_iqm_rc_rate;
- enum DRXPowerMode m_currentPowerMode;
+ enum drx_power_mode m_current_power_mode;
/* when true, avoids other devices to use the I2C bus */
bool drxk_i2c_exclusive_lock;
@@ -337,7 +342,7 @@ struct drxk_state {
* at struct drxk_config.
*/
- u16 UIO_mask; /* Bits used by UIO */
+ u16 uio_mask; /* Bits used by UIO */
bool enable_merr_cfg;
bool single_master;
diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
index 117a56926dca..93596e0e640b 100644
--- a/drivers/media/dvb-frontends/stb0899_algo.c
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
@@ -226,8 +226,8 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
next_loop--;
if (next_loop) {
- STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
- STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
}
internal->direction = -internal->direction; /* Change zigzag direction */
@@ -235,7 +235,7 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
if (internal->status == TIMINGOK) {
stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
- internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+ internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
}
@@ -306,8 +306,8 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
stb0899_write_reg(state, STB0899_CFD, reg);
- STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
- STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
}
}
@@ -317,7 +317,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
if (internal->status == CARRIEROK) {
stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
- internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+ internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
} else {
internal->derot_freq = last_derot_freq;
@@ -412,8 +412,8 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
stb0899_write_reg(state, STB0899_CFD, reg);
- STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
- STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+ STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
stb0899_check_carrier(state);
@@ -425,7 +425,15 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
if (internal->status == DATAOK) {
stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
- internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+
+ /* store autodetected IQ swapping as default for DVB-S2 tuning */
+ reg = stb0899_read_reg(state, STB0899_IQSWAP);
+ if (STB0899_GETFIELD(SYM, reg))
+ internal->inversion = IQ_SWAP_ON;
+ else
+ internal->inversion = IQ_SWAP_OFF;
+
+ internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
}
@@ -444,7 +452,7 @@ static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
int range_offst, tp_freq;
range_offst = internal->srch_range / 2000;
- tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
+ tp_freq = internal->freq - (internal->derot_freq * internal->mclk) / 1000;
if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
internal->status = RANGEOK;
@@ -638,7 +646,7 @@ enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
"RANGE OK ! derot freq=%d, mclk=%d",
internal->derot_freq, internal->mclk);
- internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
+ internal->freq = params->freq - ((internal->derot_freq * internal->mclk) / 1000);
reg = stb0899_read_reg(state, STB0899_PLPARM);
internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
dprintk(state->verbose, FE_DEBUG, 1,
@@ -1373,9 +1381,6 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
case IQ_SWAP_ON:
STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
break;
- case IQ_SWAP_AUTO: /* use last successful search first */
- STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
- break;
}
stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
stb0899_dvbs2_reacquire(state);
@@ -1405,41 +1410,39 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
}
if (internal->status != DVBS2_FEC_LOCK) {
- if (internal->inversion == IQ_SWAP_AUTO) {
- reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
- iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
- /* IQ Spectrum Inversion */
- STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
- stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
- /* start acquistion process */
- stb0899_dvbs2_reacquire(state);
+ reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+ iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
+ /* IQ Spectrum Inversion */
+ STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
+ stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+ /* start acquistion process */
+ stb0899_dvbs2_reacquire(state);
+
+ /* Wait for demod lock (UWP and CSM) */
+ internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+ if (internal->status == DVBS2_DEMOD_LOCK) {
+ i = 0;
+ /* Demod Locked, check FEC */
+ internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+ /*try thrice for false locks, (UWP and CSM Locked but no FEC) */
+ while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+ /* Read the frequency offset*/
+ offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
- /* Wait for demod lock (UWP and CSM) */
- internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
- if (internal->status == DVBS2_DEMOD_LOCK) {
- i = 0;
- /* Demod Locked, check FEC */
- internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
- /*try thrice for false locks, (UWP and CSM Locked but no FEC) */
- while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
- /* Read the frequency offset*/
- offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
-
- /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
- reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
- STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
- stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
-
- stb0899_dvbs2_reacquire(state);
- internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
- i++;
- }
+ /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+ reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+ STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+ stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+
+ stb0899_dvbs2_reacquire(state);
+ internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+ i++;
}
+ }
/*
- if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
- pParams->IQLocked = !iqSpectrum;
+ if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
+ pParams->IQLocked = !iqSpectrum;
*/
- }
}
if (internal->status == DVBS2_FEC_LOCK) {
dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
@@ -1487,13 +1490,21 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
/* Store signal parameters */
offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+ /* sign extend 30 bit value before using it in calculations */
+ if (offsetfreq & (1 << 29))
+ offsetfreq |= -1 << 30;
+
offsetfreq = offsetfreq / ((1 << 30) / 1000);
offsetfreq *= (internal->master_clk / 1000000);
+
+ /* store current inversion for next run */
reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
- offsetfreq *= -1;
+ internal->inversion = IQ_SWAP_ON;
+ else
+ internal->inversion = IQ_SWAP_OFF;
- internal->freq = internal->freq - offsetfreq;
+ internal->freq = internal->freq + offsetfreq;
internal->srate = stb0899_dvbs2_get_srate(state);
reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index cc278b3d6d5a..3dd5714eadba 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -1618,19 +1618,18 @@ static struct dvb_frontend_ops stb0899_ops = {
struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
{
struct stb0899_state *state = NULL;
- enum stb0899_inversion inversion;
state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
if (state == NULL)
goto error;
- inversion = config->inversion;
state->verbose = &verbose;
state->config = config;
state->i2c = i2c;
state->frontend.ops = stb0899_ops;
state->frontend.demodulator_priv = state;
- state->internal.inversion = inversion;
+ /* use configured inversion as default -- we'll later autodetect inversion */
+ state->internal.inversion = config->inversion;
stb0899_wakeup(&state->frontend);
if (stb0899_get_dev_id(state) == -ENODEV) {
diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
index 8d26ff6eb1db..139264d19263 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.h
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
@@ -45,9 +45,8 @@ struct stb0899_s2_reg {
};
enum stb0899_inversion {
- IQ_SWAP_OFF = 0,
- IQ_SWAP_ON,
- IQ_SWAP_AUTO
+ IQ_SWAP_OFF = +1, /* inversion affects the sign of e. g. */
+ IQ_SWAP_ON = -1, /* the derotator frequency register */
};
#define STB0899_GPIO00 0xf140
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index f981d50a2a8c..b2cd8ca51af7 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -245,6 +245,15 @@ config VIDEO_KS0127
To compile this driver as a module, choose M here: the
module will be called ks0127.
+config VIDEO_ML86V7667
+ tristate "OKI ML86V7667 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the OKI Semiconductor ML86V7667 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ml86v7667.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -425,6 +434,15 @@ config VIDEO_AK881X
help
Video output driver for AKM AK8813 and AK8814 TV encoders
+config VIDEO_THS8200
+ tristate "Texas Instruments THS8200 video encoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Texas Instruments THS8200 video encoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ths8200.
+
comment "Camera sensor devices"
config VIDEO_APTINA_PLL
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 720f42d9d9f4..dc20653bb5ad 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_VIDEO_BT856) += bt856.o
obj-$(CONFIG_VIDEO_BT866) += bt866.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_THS8200) += ths8200.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
@@ -70,3 +71,4 @@ obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 58344b6c3a55..ba4364dfae66 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -32,7 +32,6 @@
#include <linux/workqueue.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/ad9389b.h>
@@ -343,12 +342,6 @@ static const struct v4l2_ctrl_ops ad9389b_ctrl_ops = {
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = ad9389b_rd(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -356,24 +349,11 @@ static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
ad9389b_wr(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
#endif
-static int ad9389b_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_AD9389B, 0);
-}
-
static int ad9389b_log_status(struct v4l2_subdev *sd)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
@@ -600,7 +580,6 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
.log_status = ad9389b_log_status,
- .g_chip_ident = ad9389b_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ad9389b_g_register,
.s_register = ad9389b_s_register,
@@ -1188,15 +1167,14 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
client->addr << 1);
- state = kzalloc(sizeof(struct ad9389b_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
/* Platform data */
if (pdata == NULL) {
v4l_err(client, "No platform data!\n");
- err = -ENODEV;
- goto err_free;
+ return -ENODEV;
}
memcpy(&state->pdata, pdata, sizeof(state->pdata));
@@ -1251,12 +1229,14 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1));
if (state->edid_i2c_client == NULL) {
v4l2_err(sd, "failed to register edid i2c client\n");
+ err = -ENOMEM;
goto err_entity;
}
state->work_queue = create_singlethread_workqueue(sd->name);
if (state->work_queue == NULL) {
v4l2_err(sd, "could not create workqueue\n");
+ err = -ENOMEM;
goto err_unreg;
}
@@ -1276,8 +1256,6 @@ err_entity:
media_entity_cleanup(&sd->entity);
err_hdl:
v4l2_ctrl_handler_free(&state->hdl);
-err_free:
- kfree(state);
return err;
}
@@ -1302,15 +1280,14 @@ static int ad9389b_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- kfree(get_ad9389b_state(sd));
return 0;
}
/* ----------------------------------------------------------------------- */
static struct i2c_device_id ad9389b_id[] = {
- { "ad9389b", V4L2_IDENT_AD9389B },
- { "ad9889b", V4L2_IDENT_AD9389B },
+ { "ad9389b", 0 },
+ { "ad9889b", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad9389b_id);
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index ef75abe5984c..873fe1949e98 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -417,7 +417,7 @@ static int adp1653_probe(struct i2c_client *client,
if (client->dev.platform_data == NULL)
return -ENODEV;
- flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+ flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
if (flash == NULL)
return -ENOMEM;
@@ -443,7 +443,6 @@ static int adp1653_probe(struct i2c_client *client,
free_and_quit:
v4l2_ctrl_handler_free(&flash->ctrls);
- kfree(flash);
return ret;
}
@@ -455,7 +454,7 @@ static int adp1653_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&flash->subdev);
v4l2_ctrl_handler_free(&flash->ctrls);
media_entity_cleanup(&flash->subdev.entity);
- kfree(flash);
+
return 0;
}
diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c
index 6bc01fb98ff8..04bb29720aaf 100644
--- a/drivers/media/i2c/adv7170.c
+++ b/drivers/media/i2c/adv7170.c
@@ -36,7 +36,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
@@ -317,19 +316,8 @@ static int adv7170_s_fmt(struct v4l2_subdev *sd,
return ret;
}
-static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
-}
-
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops adv7170_core_ops = {
- .g_chip_ident = adv7170_g_chip_ident,
-};
-
static const struct v4l2_subdev_video_ops adv7170_video_ops = {
.s_std_output = adv7170_s_std_output,
.s_routing = adv7170_s_routing,
@@ -339,7 +327,6 @@ static const struct v4l2_subdev_video_ops adv7170_video_ops = {
};
static const struct v4l2_subdev_ops adv7170_ops = {
- .core = &adv7170_core_ops,
.video = &adv7170_video_ops,
};
@@ -359,7 +346,7 @@ static int adv7170_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
+ encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
sd = &encoder->sd;
@@ -384,7 +371,6 @@ static int adv7170_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_adv7170(sd));
return 0;
}
diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c
index c7640fab5730..b88f3b3d5ed9 100644
--- a/drivers/media/i2c/adv7175.c
+++ b/drivers/media/i2c/adv7175.c
@@ -32,7 +32,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
@@ -355,13 +354,6 @@ static int adv7175_s_fmt(struct v4l2_subdev *sd,
return ret;
}
-static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- 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)
@@ -375,7 +367,6 @@ static int adv7175_s_power(struct v4l2_subdev *sd, int on)
/* ----------------------------------------------------------------------- */
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,
};
@@ -409,7 +400,7 @@ static int adv7175_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
+ encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
sd = &encoder->sd;
@@ -434,7 +425,6 @@ static int adv7175_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_adv7175(sd));
return 0;
}
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index afd561ab190d..d7d99f1c69e4 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1,6 +1,8 @@
/*
* adv7180.c Analog Devices ADV7180 video decoder driver
* Copyright (c) 2009 Intel Corporation
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions Corp.
*
* 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
@@ -27,7 +29,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/mutex.h>
#define ADV7180_INPUT_CONTROL_REG 0x00
@@ -272,14 +273,6 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
return ret;
}
-static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
-}
-
static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7180_state *state = to_state(sd);
@@ -397,14 +390,57 @@ static void adv7180_exit_controls(struct adv7180_state *state)
v4l2_ctrl_handler_free(&state->ctrl_hdl);
}
+static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index > 0)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ return 0;
+}
+
+static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct adv7180_state *state = to_state(sd);
+
+ fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->width = 720;
+ fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
+
+ return 0;
+}
+
+static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ /*
+ * The ADV7180 sensor supports BT.601/656 output modes.
+ * The BT.656 is default and not yet configurable by s/w.
+ */
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_BT656;
+
+ return 0;
+}
+
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
+ .enum_mbus_fmt = adv7180_enum_mbus_fmt,
+ .try_mbus_fmt = adv7180_mbus_fmt,
+ .g_mbus_fmt = adv7180_mbus_fmt,
+ .s_mbus_fmt = adv7180_mbus_fmt,
+ .g_mbus_config = adv7180_g_mbus_config,
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .g_chip_ident = adv7180_g_chip_ident,
.s_std = adv7180_s_std,
};
@@ -555,7 +591,7 @@ static int adv7180_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr, client->adapter->name);
- state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL) {
ret = -ENOMEM;
goto err;
@@ -582,7 +618,6 @@ err_free_ctrl:
err_unreg_subdev:
mutex_destroy(&state->mutex);
v4l2_device_unregister_subdev(sd);
- kfree(state);
err:
printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
return ret;
@@ -607,7 +642,6 @@ static int adv7180_remove(struct i2c_client *client)
mutex_destroy(&state->mutex);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
@@ -616,9 +650,10 @@ static const struct i2c_device_id adv7180_id[] = {
{},
};
-#ifdef CONFIG_PM
-static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int adv7180_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
@@ -628,8 +663,9 @@ static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
-static int adv7180_resume(struct i2c_client *client)
+static int adv7180_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct adv7180_state *state = to_state(sd);
int ret;
@@ -643,6 +679,12 @@ static int adv7180_resume(struct i2c_client *client)
return ret;
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
+#define ADV7180_PM_OPS (&adv7180_pm_ops)
+
+#else
+#define ADV7180_PM_OPS NULL
#endif
MODULE_DEVICE_TABLE(i2c, adv7180_id);
@@ -651,13 +693,10 @@ static struct i2c_driver adv7180_driver = {
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
+ .pm = ADV7180_PM_OPS,
},
.probe = adv7180_probe,
.remove = adv7180_remove,
-#ifdef CONFIG_PM
- .suspend = adv7180_suspend,
- .resume = adv7180_resume,
-#endif
.id_table = adv7180_id,
};
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index 56a1fa4af0fe..6f738d8e3a8f 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -28,7 +28,6 @@
#include <linux/videodev2.h>
#include <media/adv7183.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -375,28 +374,28 @@ static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
reg = adv7183_read(sd, ADV7183_STATUS_1);
switch ((reg >> 0x4) & 0x7) {
case 0:
- *std = V4L2_STD_NTSC;
+ *std &= V4L2_STD_NTSC;
break;
case 1:
- *std = V4L2_STD_NTSC_443;
+ *std &= V4L2_STD_NTSC_443;
break;
case 2:
- *std = V4L2_STD_PAL_M;
+ *std &= V4L2_STD_PAL_M;
break;
case 3:
- *std = V4L2_STD_PAL_60;
+ *std &= V4L2_STD_PAL_60;
break;
case 4:
- *std = V4L2_STD_PAL;
+ *std &= V4L2_STD_PAL;
break;
case 5:
- *std = V4L2_STD_SECAM;
+ *std &= V4L2_STD_SECAM;
break;
case 6:
- *std = V4L2_STD_PAL_Nc;
+ *std &= V4L2_STD_PAL_Nc;
break;
case 7:
- *std = V4L2_STD_SECAM;
+ *std &= V4L2_STD_SECAM;
break;
default:
*std = V4L2_STD_UNKNOWN;
@@ -474,34 +473,16 @@ static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
struct adv7183 *decoder = to_adv7183(sd);
if (enable)
- gpio_direction_output(decoder->oe_pin, 0);
+ gpio_set_value(decoder->oe_pin, 0);
else
- gpio_direction_output(decoder->oe_pin, 1);
+ gpio_set_value(decoder->oe_pin, 1);
udelay(1);
return 0;
}
-static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- int rev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- /* 0x11 for adv7183, 0x13 for adv7183b */
- rev = adv7183_read(sd, ADV7183_IDENT);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = adv7183_read(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -509,12 +490,6 @@ static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
@@ -529,7 +504,6 @@ static const struct v4l2_subdev_core_ops adv7183_core_ops = {
.g_std = adv7183_g_std,
.s_std = adv7183_s_std,
.reset = adv7183_reset,
- .g_chip_ident = adv7183_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7183_g_register,
.s_register = adv7183_s_register,
@@ -573,23 +547,24 @@ static int adv7183_probe(struct i2c_client *client,
if (pin_array == NULL)
return -EINVAL;
- decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (decoder == NULL)
return -ENOMEM;
decoder->reset_pin = pin_array[0];
decoder->oe_pin = pin_array[1];
- if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+ if (devm_gpio_request_one(&client->dev, decoder->reset_pin,
+ GPIOF_OUT_INIT_LOW, "ADV7183 Reset")) {
v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
- ret = -EBUSY;
- goto err_free_decoder;
+ return -EBUSY;
}
- if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+ if (devm_gpio_request_one(&client->dev, decoder->oe_pin,
+ GPIOF_OUT_INIT_HIGH,
+ "ADV7183 Output Enable")) {
v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
- ret = -EBUSY;
- goto err_free_reset;
+ return -EBUSY;
}
sd = &decoder->sd;
@@ -611,7 +586,7 @@ static int adv7183_probe(struct i2c_client *client,
ret = hdl->error;
v4l2_ctrl_handler_free(hdl);
- goto err_free_oe;
+ return ret;
}
/* v4l2 doesn't support an autodetect standard, pick PAL as default */
@@ -619,12 +594,10 @@ static int adv7183_probe(struct i2c_client *client,
decoder->input = ADV7183_COMPOSITE4;
decoder->output = ADV7183_8BIT_OUT;
- gpio_direction_output(decoder->oe_pin, 1);
/* reset chip */
- gpio_direction_output(decoder->reset_pin, 0);
/* reset pulse width at least 5ms */
mdelay(10);
- gpio_direction_output(decoder->reset_pin, 1);
+ gpio_set_value(decoder->reset_pin, 1);
/* wait 5ms before any further i2c writes are performed */
mdelay(5);
@@ -638,29 +611,18 @@ static int adv7183_probe(struct i2c_client *client,
ret = v4l2_ctrl_handler_setup(hdl);
if (ret) {
v4l2_ctrl_handler_free(hdl);
- goto err_free_oe;
+ return ret;
}
return 0;
-err_free_oe:
- gpio_free(decoder->oe_pin);
-err_free_reset:
- gpio_free(decoder->reset_pin);
-err_free_decoder:
- kfree(decoder);
- return ret;
}
static int adv7183_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct adv7183 *decoder = to_adv7183(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- gpio_free(decoder->oe_pin);
- gpio_free(decoder->reset_pin);
- kfree(decoder);
return 0;
}
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index 9fc2b985df0e..7606218ec4a7 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -28,7 +28,6 @@
#include <media/adv7343.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include "adv7343_regs.h"
@@ -311,21 +310,12 @@ static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
-}
-
static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
.s_ctrl = adv7343_s_ctrl,
};
static const struct v4l2_subdev_core_ops adv7343_core_ops = {
.log_status = adv7343_log_status,
- .g_chip_ident = adv7343_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c
index 3dc6098c7267..558f19154eb9 100644
--- a/drivers/media/i2c/adv7393.c
+++ b/drivers/media/i2c/adv7393.c
@@ -33,7 +33,6 @@
#include <media/adv7393.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include "adv7393_regs.h"
@@ -301,21 +300,12 @@ static int adv7393_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int adv7393_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7393, 0);
-}
-
static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
.s_ctrl = adv7393_s_ctrl,
};
static const struct v4l2_subdev_core_ops adv7393_core_ops = {
.log_status = adv7393_log_status,
- .g_chip_ident = adv7393_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -410,7 +400,7 @@ static int adv7393_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct adv7393_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -444,16 +434,13 @@ static int adv7393_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
v4l2_ctrl_handler_setup(&state->hdl);
err = adv7393_initialize(&state->sd);
- if (err) {
+ if (err)
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
- }
return err;
}
@@ -464,7 +451,6 @@ static int adv7393_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 31a63c9324fe..1d675b58fd71 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -38,7 +38,6 @@
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <media/adv7604.h>
static int debug;
@@ -643,12 +642,6 @@ static void adv7604_inv_register(struct v4l2_subdev *sd)
static int adv7604_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->size = 1;
switch (reg->reg >> 8) {
case 0:
@@ -701,12 +694,6 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
static int adv7604_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
switch (reg->reg >> 8) {
case 0:
io_write(sd, reg->reg & 0xff, reg->val & 0xff);
@@ -984,14 +971,6 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int adv7604_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7604, 0);
-}
-
/* ----------------------------------------------------------------------- */
static inline bool no_power(struct v4l2_subdev *sd)
@@ -1787,7 +1766,6 @@ static const struct v4l2_subdev_core_ops adv7604_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .g_chip_ident = adv7604_g_chip_ident,
.interrupt_service_routine = adv7604_isr,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7604_g_register,
@@ -1968,7 +1946,7 @@ static int adv7604_probe(struct i2c_client *client,
v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n",
client->addr << 1);
- state = kzalloc(sizeof(struct adv7604_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (!state) {
v4l_err(client, "Could not allocate adv7604_state memory!\n");
return -ENOMEM;
@@ -1977,8 +1955,7 @@ static int adv7604_probe(struct i2c_client *client,
/* platform data */
if (!pdata) {
v4l_err(client, "No platform data!\n");
- err = -ENODEV;
- goto err_state;
+ return -ENODEV;
}
memcpy(&state->pdata, pdata, sizeof(state->pdata));
@@ -1991,8 +1968,7 @@ static int adv7604_probe(struct i2c_client *client,
if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
v4l2_info(sd, "not an adv7604 on address 0x%x\n",
client->addr << 1);
- err = -ENODEV;
- goto err_state;
+ return -ENODEV;
}
/* control handlers */
@@ -2093,8 +2069,6 @@ err_i2c:
adv7604_unregister_clients(state);
err_hdl:
v4l2_ctrl_handler_free(hdl);
-err_state:
- kfree(state);
return err;
}
@@ -2111,7 +2085,6 @@ static int adv7604_remove(struct i2c_client *client)
media_entity_cleanup(&sd->entity);
adv7604_unregister_clients(to_state(sd));
v4l2_ctrl_handler_free(sd->ctrl_handler);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index fd47465e4f6a..c14e66756b98 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <media/ak881x.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@@ -33,7 +32,6 @@ struct ak881x {
struct v4l2_subdev subdev;
struct ak881x_pdata *pdata;
unsigned int lines;
- int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */
char revision; /* DEVICE_REVISION content */
};
@@ -62,36 +60,16 @@ static struct ak881x *to_ak881x(const struct i2c_client *client)
return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
}
-static int ak881x_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ak881x *ak881x = to_ak881x(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = ak881x->id;
- id->revision = ak881x->revision;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ak881x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+ if (reg->reg > 0x26)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
+ reg->size = 1;
reg->val = reg_read(client, reg->reg);
if (reg->val > 0xffff)
@@ -105,12 +83,9 @@ static int ak881x_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+ if (reg->reg > 0x26)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -229,7 +204,6 @@ static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
}
static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
- .g_chip_ident = ak881x_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ak881x_g_register,
.s_register = ak881x_s_register,
@@ -264,7 +238,7 @@ static int ak881x_probe(struct i2c_client *client,
return -EIO;
}
- ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL);
+ ak881x = devm_kzalloc(&client->dev, sizeof(*ak881x), GFP_KERNEL);
if (!ak881x)
return -ENOMEM;
@@ -274,15 +248,11 @@ static int ak881x_probe(struct i2c_client *client,
switch (data) {
case 0x13:
- ak881x->id = V4L2_IDENT_AK8813;
- break;
case 0x14:
- ak881x->id = V4L2_IDENT_AK8814;
break;
default:
dev_err(&client->dev,
"No ak881x chip detected, register read %x\n", data);
- kfree(ak881x);
return -ENODEV;
}
@@ -331,7 +301,6 @@ static int ak881x_remove(struct i2c_client *client)
struct ak881x *ak881x = to_ak881x(client);
v4l2_device_unregister_subdev(&ak881x->subdev);
- kfree(ak881x);
return 0;
}
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
index 58d523f2648f..301084b07887 100644
--- a/drivers/media/i2c/as3645a.c
+++ b/drivers/media/i2c/as3645a.c
@@ -813,7 +813,7 @@ static int as3645a_probe(struct i2c_client *client,
if (client->dev.platform_data == NULL)
return -ENODEV;
- flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+ flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
if (flash == NULL)
return -ENOMEM;
@@ -838,10 +838,8 @@ static int as3645a_probe(struct i2c_client *client,
flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
done:
- if (ret < 0) {
+ if (ret < 0)
v4l2_ctrl_handler_free(&flash->ctrls);
- kfree(flash);
- }
return ret;
}
@@ -855,7 +853,6 @@ static int as3645a_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&flash->ctrls);
media_entity_cleanup(&flash->subdev.entity);
mutex_destroy(&flash->power_lock);
- kfree(flash);
return 0;
}
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
index 377bf05b1efd..369cf6ff88f7 100644
--- a/drivers/media/i2c/bt819.c
+++ b/drivers/media/i2c/bt819.c
@@ -36,7 +36,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/bt819.h>
@@ -57,7 +56,6 @@ struct bt819 {
unsigned char reg[32];
v4l2_std_id norm;
- int ident;
int input;
int enable;
};
@@ -217,15 +215,17 @@ static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
struct bt819 *decoder = to_bt819(sd);
int status = bt819_read(decoder, 0x00);
int res = V4L2_IN_ST_NO_SIGNAL;
- v4l2_std_id std;
+ v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
if ((status & 0x80))
res = 0;
+ else
+ std = V4L2_STD_UNKNOWN;
if ((status & 0x10))
- std = V4L2_STD_PAL;
+ std &= V4L2_STD_PAL;
else
- std = V4L2_STD_NTSC;
+ std &= V4L2_STD_NTSC;
if (pstd)
*pstd = std;
if (pstatus)
@@ -373,14 +373,6 @@ static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct bt819 *decoder = to_bt819(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
@@ -388,7 +380,6 @@ static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
};
static const struct v4l2_subdev_core_ops bt819_core_ops = {
- .g_chip_ident = bt819_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -425,7 +416,7 @@ static int bt819_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (decoder == NULL)
return -ENOMEM;
sd = &decoder->sd;
@@ -435,15 +426,12 @@ static int bt819_probe(struct i2c_client *client,
switch (ver & 0xf0) {
case 0x70:
name = "bt819a";
- decoder->ident = V4L2_IDENT_BT819A;
break;
case 0x60:
name = "bt817a";
- decoder->ident = V4L2_IDENT_BT817A;
break;
case 0x20:
name = "bt815a";
- decoder->ident = V4L2_IDENT_BT815A;
break;
default:
v4l2_dbg(1, debug, sd,
@@ -476,7 +464,6 @@ static int bt819_probe(struct i2c_client *client,
int err = decoder->hdl.error;
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return err;
}
v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -490,7 +477,6 @@ static int bt819_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return 0;
}
diff --git a/drivers/media/i2c/bt856.c b/drivers/media/i2c/bt856.c
index 7e5bd365c239..7fc163d0253c 100644
--- a/drivers/media/i2c/bt856.c
+++ b/drivers/media/i2c/bt856.c
@@ -36,7 +36,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -177,17 +176,9 @@ static int bt856_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops bt856_core_ops = {
- .g_chip_ident = bt856_g_chip_ident,
.init = bt856_init,
};
@@ -216,7 +207,7 @@ static int bt856_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
+ encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
sd = &encoder->sd;
@@ -250,7 +241,6 @@ static int bt856_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_bt856(sd));
return 0;
}
diff --git a/drivers/media/i2c/bt866.c b/drivers/media/i2c/bt866.c
index 905320b67a1c..a8bf10fc665d 100644
--- a/drivers/media/i2c/bt866.c
+++ b/drivers/media/i2c/bt866.c
@@ -36,7 +36,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -175,26 +174,14 @@ static int bt866_s_routing(struct v4l2_subdev *sd,
bt866_write(client, 0xdc, val);
#endif
-static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
-}
-
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops bt866_core_ops = {
- .g_chip_ident = bt866_g_chip_ident,
-};
-
static const struct v4l2_subdev_video_ops bt866_video_ops = {
.s_std_output = bt866_s_std_output,
.s_routing = bt866_s_routing,
};
static const struct v4l2_subdev_ops bt866_ops = {
- .core = &bt866_core_ops,
.video = &bt866_video_ops,
};
@@ -207,7 +194,7 @@ static int bt866_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+ encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
sd = &encoder->sd;
@@ -220,7 +207,6 @@ static int bt866_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_bt866(sd));
return 0;
}
diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c
index 1d2f7c8512b5..34b76a9e7515 100644
--- a/drivers/media/i2c/cs5345.c
+++ b/drivers/media/i2c/cs5345.c
@@ -24,7 +24,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
@@ -99,12 +98,6 @@ static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl)
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->size = 1;
reg->val = cs5345_read(sd, reg->reg & 0x1f);
return 0;
@@ -112,24 +105,11 @@ static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
static int cs5345_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
return 0;
}
#endif
-static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
-}
-
static int cs5345_log_status(struct v4l2_subdev *sd)
{
u8 v = cs5345_read(sd, 0x09) & 7;
@@ -152,7 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
static const struct v4l2_subdev_core_ops cs5345_core_ops = {
.log_status = cs5345_log_status,
- .g_chip_ident = cs5345_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -190,7 +169,7 @@ static int cs5345_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -206,7 +185,6 @@ static int cs5345_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
/* set volume/mute */
@@ -227,7 +205,6 @@ static int cs5345_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c
index b293912206eb..27400c16ef9a 100644
--- a/drivers/media/i2c/cs53l32a.c
+++ b/drivers/media/i2c/cs53l32a.c
@@ -28,7 +28,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
@@ -104,14 +103,6 @@ static int cs53l32a_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client,
- chip, V4L2_IDENT_CS53l32A, 0);
-}
-
static int cs53l32a_log_status(struct v4l2_subdev *sd)
{
struct cs53l32a_state *state = to_state(sd);
@@ -130,7 +121,6 @@ static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = {
static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
.log_status = cs53l32a_log_status,
- .g_chip_ident = cs53l32a_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -175,7 +165,7 @@ static int cs53l32a_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -197,7 +187,6 @@ static int cs53l32a_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
@@ -228,7 +217,6 @@ static int cs53l32a_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 12fb9b2eb887..2e3771d57354 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -45,7 +45,6 @@
#include <linux/delay.h>
#include <linux/math64.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
#include "cx25840-core.h"
@@ -498,7 +497,7 @@ static void cx23885_initialize(struct i2c_client *client)
/* Sys PLL */
switch (state->id) {
- case V4L2_IDENT_CX23888_AV:
+ case CX23888_AV:
/*
* 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
@@ -511,7 +510,7 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x42c, 0x42600000);
cx25840_write4(client, 0x44c, 0x161f1000);
break;
- case V4L2_IDENT_CX23887_AV:
+ case CX23887_AV:
/*
* 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
@@ -519,7 +518,7 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x11c, 0x01d1744c);
cx25840_write4(client, 0x118, 0x00000416);
break;
- case V4L2_IDENT_CX23885_AV:
+ case CX23885_AV:
default:
/*
* 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
@@ -546,7 +545,7 @@ static void cx23885_initialize(struct i2c_client *client)
/* HVR1850 */
switch (state->id) {
- case V4L2_IDENT_CX23888_AV:
+ case CX23888_AV:
/* 888/HVR1250 specific */
cx25840_write4(client, 0x10c, 0x13333333);
cx25840_write4(client, 0x108, 0x00000515);
@@ -570,7 +569,7 @@ static void cx23885_initialize(struct i2c_client *client)
* 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
*/
switch (state->id) {
- case V4L2_IDENT_CX23888_AV:
+ case CX23888_AV:
/*
* 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
* 368.64 MHz before post divide
@@ -580,7 +579,7 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x114, 0x017dbf48);
cx25840_write4(client, 0x110, 0x000a030e);
break;
- case V4L2_IDENT_CX23887_AV:
+ case CX23887_AV:
/*
* 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
* 368.64 MHz before post divide
@@ -589,7 +588,7 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x114, 0x017dbf48);
cx25840_write4(client, 0x110, 0x000a030e);
break;
- case V4L2_IDENT_CX23885_AV:
+ case CX23885_AV:
default:
/*
* 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
@@ -1662,10 +1661,6 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->size = 1;
reg->val = cx25840_read(client, reg->reg & 0x0fff);
return 0;
@@ -1675,10 +1670,6 @@ static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
return 0;
}
@@ -1938,14 +1929,6 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
return 0;
}
-static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct cx25840_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
static int cx25840_log_status(struct v4l2_subdev *sd)
{
struct cx25840_state *state = to_state(sd);
@@ -5051,7 +5034,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,
- .g_chip_ident = cx25840_g_chip_ident,
.g_ctrl = v4l2_subdev_g_ctrl,
.s_ctrl = v4l2_subdev_s_ctrl,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -5128,18 +5110,18 @@ static u32 get_cx2388x_ident(struct i2c_client *client)
ret = cx25840_read4(client, 0x300);
if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
/* No DIF */
- ret = V4L2_IDENT_CX23885_AV;
+ ret = CX23885_AV;
} else {
/* CX23887 has a broken DIF, but the registers
* appear valid (but unused), good enough to detect. */
- ret = V4L2_IDENT_CX23887_AV;
+ ret = CX23887_AV;
}
} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
- ret = V4L2_IDENT_CX23888_AV;
+ ret = CX23888_AV;
} else {
v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
- ret = V4L2_IDENT_CX23887_AV;
+ ret = CX23887_AV;
}
/* Back into digital power down */
@@ -5153,7 +5135,7 @@ static int cx25840_probe(struct i2c_client *client,
struct cx25840_state *state;
struct v4l2_subdev *sd;
int default_volume;
- u32 id = V4L2_IDENT_NONE;
+ u32 id;
u16 device_id;
/* Check if the adapter supports the needed features */
@@ -5169,14 +5151,14 @@ static int cx25840_probe(struct i2c_client *client,
/* The high byte of the device ID should be
* 0x83 for the cx2583x and 0x84 for the cx2584x */
if ((device_id & 0xff00) == 0x8300) {
- id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ id = CX25836 + ((device_id >> 4) & 0xf) - 6;
} else if ((device_id & 0xff00) == 0x8400) {
- id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+ id = CX25840 + ((device_id >> 4) & 0xf);
} else if (device_id == 0x0000) {
id = get_cx2388x_ident(client);
} else if ((device_id & 0xfff0) == 0x5A30) {
/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
- id = V4L2_IDENT_CX2310X_AV;
+ id = CX2310X_AV;
} else if ((device_id & 0xff) == (device_id >> 8)) {
v4l_err(client,
"likely a confused/unresponsive cx2388[578] A/V decoder"
@@ -5190,7 +5172,7 @@ static int cx25840_probe(struct i2c_client *client,
return -ENODEV;
}
- state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -5198,26 +5180,26 @@ static int cx25840_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
switch (id) {
- case V4L2_IDENT_CX23885_AV:
+ case CX23885_AV:
v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
break;
- case V4L2_IDENT_CX23887_AV:
+ case CX23887_AV:
v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
break;
- case V4L2_IDENT_CX23888_AV:
+ case CX23888_AV:
v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
break;
- case V4L2_IDENT_CX2310X_AV:
+ case CX2310X_AV:
v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
device_id, client->addr << 1, client->adapter->name);
break;
- case V4L2_IDENT_CX25840:
- case V4L2_IDENT_CX25841:
- case V4L2_IDENT_CX25842:
- case V4L2_IDENT_CX25843:
+ case CX25840:
+ case CX25841:
+ case CX25842:
+ case CX25843:
/* Note: revision '(device_id & 0x0f) == 2' was never built. The
marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
@@ -5226,8 +5208,8 @@ static int cx25840_probe(struct i2c_client *client,
: (device_id & 0x0f),
client->addr << 1, client->adapter->name);
break;
- case V4L2_IDENT_CX25836:
- case V4L2_IDENT_CX25837:
+ case CX25836:
+ case CX25837:
default:
v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4, device_id & 0x0f,
@@ -5292,7 +5274,6 @@ static int cx25840_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
if (!is_cx2583x(state))
@@ -5317,7 +5298,6 @@ static int cx25840_remove(struct i2c_client *client)
cx25840_ir_remove(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
index bd4ada28b490..37bc04217c44 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.h
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
@@ -23,12 +23,24 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <linux/i2c.h>
struct cx25840_ir_state;
+enum cx25840_model {
+ CX23885_AV,
+ CX23887_AV,
+ CX23888_AV,
+ CX2310X_AV,
+ CX25840,
+ CX25841,
+ CX25842,
+ CX25843,
+ CX25836,
+ CX25837,
+};
+
struct cx25840_state {
struct i2c_client *c;
struct v4l2_subdev sd;
@@ -46,7 +58,7 @@ struct cx25840_state {
u32 audclk_freq;
int audmode;
int vbi_line_offset;
- u32 id;
+ enum cx25840_model id;
u32 rev;
int is_initialized;
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
@@ -66,35 +78,35 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
static inline bool is_cx2583x(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX25836 ||
- state->id == V4L2_IDENT_CX25837;
+ return state->id == CX25836 ||
+ state->id == CX25837;
}
static inline bool is_cx231xx(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX2310X_AV;
+ return state->id == CX2310X_AV;
}
static inline bool is_cx2388x(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX23885_AV ||
- state->id == V4L2_IDENT_CX23887_AV ||
- state->id == V4L2_IDENT_CX23888_AV;
+ return state->id == CX23885_AV ||
+ state->id == CX23887_AV ||
+ state->id == CX23888_AV;
}
static inline bool is_cx23885(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX23885_AV;
+ return state->id == CX23885_AV;
}
static inline bool is_cx23887(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX23887_AV;
+ return state->id == CX23887_AV;
}
static inline bool is_cx23888(struct cx25840_state *state)
{
- return state->id == V4L2_IDENT_CX23888_AV;
+ return state->id == CX23888_AV;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 9ae977b5983a..e6588ee5bdb0 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -1230,16 +1230,14 @@ int cx25840_ir_probe(struct v4l2_subdev *sd)
if (!(is_cx23885(state) || is_cx23887(state)))
return 0;
- ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
+ ir_state = devm_kzalloc(&state->c->dev, sizeof(*ir_state), GFP_KERNEL);
if (ir_state == NULL)
return -ENOMEM;
spin_lock_init(&ir_state->rx_kfifo_lock);
if (kfifo_alloc(&ir_state->rx_kfifo,
- CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
- kfree(ir_state);
+ CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL))
return -ENOMEM;
- }
ir_state->c = state->c;
state->ir_state = ir_state;
@@ -1273,7 +1271,6 @@ int cx25840_ir_remove(struct v4l2_subdev *sd)
cx25840_ir_tx_shutdown(sd);
kfifo_free(&ir_state->rx_kfifo);
- kfree(ir_state);
state->ir_state = NULL;
return 0;
}
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 8e2f79cb045e..82bf5679da30 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -295,7 +295,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
unsigned short addr = client->addr;
int err;
- ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
+ ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL);
if (!ir)
return -ENOMEM;
@@ -398,10 +398,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
* internally
*/
rc = rc_allocate_device();
- if (!rc) {
- err = -ENOMEM;
- goto err_out_free;
- }
+ if (!rc)
+ return -ENOMEM;
}
ir->rc = rc;
@@ -454,7 +452,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
err_out_free:
/* Only frees rc if it were allocated internally */
rc_free_device(rc);
- kfree(ir);
return err;
}
@@ -470,7 +467,6 @@ static int ir_remove(struct i2c_client *client)
rc_unregister_device(ir->rc);
/* free memory */
- kfree(ir);
return 0;
}
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
index 04a6efa37cc3..c3e94ae82c03 100644
--- a/drivers/media/i2c/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
@@ -42,7 +42,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include "ks0127.h"
MODULE_DESCRIPTION("KS0127 video decoder driver");
@@ -200,7 +199,6 @@ struct adjust {
struct ks0127 {
struct v4l2_subdev sd;
v4l2_std_id norm;
- int ident;
u8 regs[256];
};
@@ -371,12 +369,9 @@ static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v)
****************************************************************************/
static void ks0127_init(struct v4l2_subdev *sd)
{
- struct ks0127 *ks = to_ks0127(sd);
u8 *table = reg_defaults;
int i;
- ks->ident = V4L2_IDENT_KS0127;
-
v4l2_dbg(1, debug, sd, "reset\n");
msleep(1);
@@ -397,7 +392,6 @@ static void ks0127_init(struct v4l2_subdev *sd)
if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) {
- ks->ident = V4L2_IDENT_KS0122S;
v4l2_dbg(1, debug, sd, "ks0122s found\n");
return;
}
@@ -408,7 +402,6 @@ static void ks0127_init(struct v4l2_subdev *sd)
break;
case 9:
- ks->ident = V4L2_IDENT_KS0127B;
v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n");
break;
@@ -616,17 +609,24 @@ static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd
{
int stat = V4L2_IN_ST_NO_SIGNAL;
u8 status;
- v4l2_std_id std = V4L2_STD_ALL;
+ v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
status = ks0127_read(sd, KS_STAT);
if (!(status & 0x20)) /* NOVID not set */
stat = 0;
- if (!(status & 0x01)) /* CLOCK set */
+ if (!(status & 0x01)) { /* CLOCK set */
stat |= V4L2_IN_ST_NO_COLOR;
- if ((status & 0x08)) /* PALDET set */
- std = V4L2_STD_PAL;
+ std = V4L2_STD_UNKNOWN;
+ } else {
+ if ((status & 0x08)) /* PALDET set */
+ std &= V4L2_STD_PAL;
+ else
+ std &= V4L2_STD_NTSC;
+ }
+ if ((status & 0x10)) /* PALDET set */
+ std &= V4L2_STD_525_60;
else
- std = V4L2_STD_NTSC;
+ std &= V4L2_STD_625_50;
if (pstd)
*pstd = std;
if (pstatus)
@@ -646,18 +646,9 @@ static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
return ks0127_status(sd, status, NULL);
}
-static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ks0127 *ks = to_ks0127(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops ks0127_core_ops = {
- .g_chip_ident = ks0127_g_chip_ident,
.s_std = ks0127_s_std,
};
@@ -685,7 +676,7 @@ static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *i
client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
client->addr << 1, client->adapter->name);
- ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+ ks = devm_kzalloc(&client->dev, sizeof(*ks), GFP_KERNEL);
if (ks == NULL)
return -ENOMEM;
sd = &ks->sd;
@@ -708,7 +699,6 @@ static int ks0127_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */
ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */
- kfree(to_ks0127(sd));
return 0;
}
diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c
index 39f50fd2b8d2..bf476358704d 100644
--- a/drivers/media/i2c/m52790.c
+++ b/drivers/media/i2c/m52790.c
@@ -29,7 +29,6 @@
#include <linux/videodev2.h>
#include <media/m52790.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
MODULE_AUTHOR("Hans Verkuil");
@@ -83,12 +82,7 @@ static int m52790_s_routing(struct v4l2_subdev *sd,
static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
struct m52790_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (reg->reg != 0)
return -EINVAL;
reg->size = 1;
@@ -99,12 +93,7 @@ static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct m52790_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (reg->reg != 0)
return -EINVAL;
state->input = reg->val & 0x0303;
@@ -114,13 +103,6 @@ static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis
}
#endif
-static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
-}
-
static int m52790_log_status(struct v4l2_subdev *sd)
{
struct m52790_state *state = to_state(sd);
@@ -136,7 +118,6 @@ static int m52790_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops m52790_core_ops = {
.log_status = m52790_log_status,
- .g_chip_ident = m52790_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = m52790_g_register,
.s_register = m52790_s_register,
@@ -174,7 +155,7 @@ static int m52790_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -191,7 +172,6 @@ static int m52790_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 0b899cb6cda1..8d870b7b43ff 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -930,6 +930,7 @@ static int m5mols_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct m5mols_platform_data *pdata = client->dev.platform_data;
+ unsigned long gpio_flags;
struct m5mols_info *info;
struct v4l2_subdev *sd;
int ret;
@@ -949,24 +950,27 @@ static int m5mols_probe(struct i2c_client *client,
return -EINVAL;
}
- info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->pdata = pdata;
info->set_power = pdata->set_power;
- ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
+ gpio_flags = pdata->reset_polarity
+ ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = devm_gpio_request_one(&client->dev, pdata->gpio_reset, gpio_flags,
+ "M5MOLS_NRST");
if (ret) {
dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
- goto out_free;
+ return ret;
}
- gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
- ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+ ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies),
+ supplies);
if (ret) {
dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
- goto out_gpio;
+ return ret;
}
sd = &info->sd;
@@ -978,17 +982,17 @@ static int m5mols_probe(struct i2c_client *client,
info->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
if (ret < 0)
- goto out_reg;
+ return ret;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
init_waitqueue_head(&info->irq_waitq);
mutex_init(&info->lock);
- ret = request_irq(client->irq, m5mols_irq_handler,
- IRQF_TRIGGER_RISING, MODULE_NAME, sd);
+ ret = devm_request_irq(&client->dev, client->irq, m5mols_irq_handler,
+ IRQF_TRIGGER_RISING, MODULE_NAME, sd);
if (ret) {
dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
- goto out_me;
+ goto error;
}
info->res_type = M5MOLS_RESTYPE_MONITOR;
info->ffmt[0] = m5mols_default_ffmt[0];
@@ -996,7 +1000,7 @@ static int m5mols_probe(struct i2c_client *client,
ret = m5mols_sensor_power(info, true);
if (ret)
- goto out_irq;
+ goto error;
ret = m5mols_fw_start(sd);
if (!ret)
@@ -1005,32 +1009,19 @@ static int m5mols_probe(struct i2c_client *client,
ret = m5mols_sensor_power(info, false);
if (!ret)
return 0;
-out_irq:
- free_irq(client->irq, sd);
-out_me:
+error:
media_entity_cleanup(&sd->entity);
-out_reg:
- regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-out_gpio:
- gpio_free(pdata->gpio_reset);
-out_free:
- kfree(info);
return ret;
}
static int m5mols_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct m5mols_info *info = to_m5mols(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- free_irq(client->irq, sd);
-
- regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
- gpio_free(info->pdata->gpio_reset);
media_entity_cleanup(&sd->entity);
- kfree(info);
+
return 0;
}
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
new file mode 100644
index 000000000000..efdc873e58d1
--- /dev/null
+++ b/drivers/media/i2c/ml86v7667.c
@@ -0,0 +1,431 @@
+/*
+ * OKI Semiconductor ML86V7667 video decoder driver
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+
+#define DRV_NAME "ml86v7667"
+
+/* Subaddresses */
+#define MRA_REG 0x00 /* Mode Register A */
+#define MRC_REG 0x02 /* Mode Register C */
+#define LUMC_REG 0x0C /* Luminance Control */
+#define CLC_REG 0x10 /* Contrast level control */
+#define SSEPL_REG 0x11 /* Sync separation level */
+#define CHRCA_REG 0x12 /* Chrominance Control A */
+#define ACCC_REG 0x14 /* ACC Loop filter & Chrominance control */
+#define ACCRC_REG 0x15 /* ACC Reference level control */
+#define HUE_REG 0x16 /* Hue control */
+#define ADC2_REG 0x1F /* ADC Register 2 */
+#define PLLR1_REG 0x20 /* PLL Register 1 */
+#define STATUS_REG 0x2C /* STATUS Register */
+
+/* Mode Register A register bits */
+#define MRA_OUTPUT_MODE_MASK (3 << 6)
+#define MRA_ITUR_BT601 (1 << 6)
+#define MRA_ITUR_BT656 (0 << 6)
+#define MRA_INPUT_MODE_MASK (7 << 3)
+#define MRA_PAL_BT601 (4 << 3)
+#define MRA_NTSC_BT601 (0 << 3)
+#define MRA_REGISTER_MODE (1 << 0)
+
+/* Mode Register C register bits */
+#define MRC_AUTOSELECT (1 << 7)
+
+/* Luminance Control register bits */
+#define LUMC_ONOFF_SHIFT 7
+#define LUMC_ONOFF_MASK (1 << 7)
+
+/* Contrast level control register bits */
+#define CLC_CONTRAST_ONOFF (1 << 7)
+#define CLC_CONTRAST_MASK 0x0F
+
+/* Sync separation level register bits */
+#define SSEPL_LUMINANCE_ONOFF (1 << 7)
+#define SSEPL_LUMINANCE_MASK 0x7F
+
+/* Chrominance Control A register bits */
+#define CHRCA_MODE_SHIFT 6
+#define CHRCA_MODE_MASK (1 << 6)
+
+/* ACC Loop filter & Chrominance control register bits */
+#define ACCC_CHROMA_CR_SHIFT 3
+#define ACCC_CHROMA_CR_MASK (7 << 3)
+#define ACCC_CHROMA_CB_SHIFT 0
+#define ACCC_CHROMA_CB_MASK (7 << 0)
+
+/* ACC Reference level control register bits */
+#define ACCRC_CHROMA_MASK 0xfc
+#define ACCRC_CHROMA_SHIFT 2
+
+/* ADC Register 2 register bits */
+#define ADC2_CLAMP_VOLTAGE_MASK (7 << 1)
+#define ADC2_CLAMP_VOLTAGE(n) ((n & 7) << 1)
+
+/* PLL Register 1 register bits */
+#define PLLR1_FIXED_CLOCK (1 << 7)
+
+/* STATUS Register register bits */
+#define STATUS_HLOCK_DETECT (1 << 3)
+#define STATUS_NTSCPAL (1 << 2)
+
+struct ml86v7667_priv {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ v4l2_std_id std;
+};
+
+static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct ml86v7667_priv, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;
+}
+
+static int ml86v7667_mask_set(struct i2c_client *client, const u8 reg,
+ const u8 mask, const u8 data)
+{
+ int val = i2c_smbus_read_byte_data(client, reg);
+ if (val < 0)
+ return val;
+
+ val = (val & ~mask) | (data & mask);
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ret = ml86v7667_mask_set(client, SSEPL_REG,
+ SSEPL_LUMINANCE_MASK, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = ml86v7667_mask_set(client, CLC_REG,
+ CLC_CONTRAST_MASK, ctrl->val);
+ break;
+ case V4L2_CID_CHROMA_GAIN:
+ ret = ml86v7667_mask_set(client, ACCRC_REG, ACCRC_CHROMA_MASK,
+ ctrl->val << ACCRC_CHROMA_SHIFT);
+ break;
+ case V4L2_CID_HUE:
+ ret = ml86v7667_mask_set(client, HUE_REG, ~0, ctrl->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = ml86v7667_mask_set(client, ACCC_REG,
+ ACCC_CHROMA_CR_MASK,
+ ctrl->val << ACCC_CHROMA_CR_SHIFT);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = ml86v7667_mask_set(client, ACCC_REG,
+ ACCC_CHROMA_CB_MASK,
+ ctrl->val << ACCC_CHROMA_CB_SHIFT);
+ break;
+ case V4L2_CID_SHARPNESS:
+ ret = ml86v7667_mask_set(client, LUMC_REG,
+ LUMC_ONOFF_MASK,
+ ctrl->val << LUMC_ONOFF_SHIFT);
+ break;
+ case V4L2_CID_COLOR_KILLER:
+ ret = ml86v7667_mask_set(client, CHRCA_REG,
+ CHRCA_MODE_MASK,
+ ctrl->val << CHRCA_MODE_SHIFT);
+ break;
+ }
+
+ return 0;
+}
+
+static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int status;
+
+ status = i2c_smbus_read_byte_data(client, STATUS_REG);
+ if (status < 0)
+ return status;
+
+ if (status & STATUS_HLOCK_DETECT)
+ *std &= status & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
+ else
+ *std = V4L2_STD_UNKNOWN;
+
+ return 0;
+}
+
+static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int status_reg;
+
+ status_reg = i2c_smbus_read_byte_data(client, STATUS_REG);
+ if (status_reg < 0)
+ return status_reg;
+
+ *status = status_reg & STATUS_HLOCK_DETECT ? 0 : V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
+static int ml86v7667_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index > 0)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ return 0;
+}
+
+static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ml86v7667_priv *priv = to_ml86v7667(sd);
+
+ fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->width = 720;
+ fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;
+
+ return 0;
+}
+
+static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_BT656;
+
+ return 0;
+}
+
+static int ml86v7667_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct ml86v7667_priv *priv = to_ml86v7667(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
+ int ret;
+ u8 mode;
+
+ /* PAL/NTSC ITU-R BT.601 input mode */
+ mode = std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
+ ret = ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, mode);
+ if (ret < 0)
+ return ret;
+
+ priv->std = std;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ml86v7667_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, (u8)reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+ reg->size = sizeof(u8);
+
+ return 0;
+}
+
+static int ml86v7667_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_write_byte_data(client, (u8)reg->reg, (u8)reg->val);
+}
+#endif
+
+static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
+ .s_ctrl = ml86v7667_s_ctrl,
+};
+
+static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
+ .querystd = ml86v7667_querystd,
+ .g_input_status = ml86v7667_g_input_status,
+ .enum_mbus_fmt = ml86v7667_enum_mbus_fmt,
+ .try_mbus_fmt = ml86v7667_mbus_fmt,
+ .g_mbus_fmt = ml86v7667_mbus_fmt,
+ .s_mbus_fmt = ml86v7667_mbus_fmt,
+ .g_mbus_config = ml86v7667_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
+ .s_std = ml86v7667_s_std,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ml86v7667_g_register,
+ .s_register = ml86v7667_s_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ml86v7667_subdev_ops = {
+ .core = &ml86v7667_subdev_core_ops,
+ .video = &ml86v7667_subdev_video_ops,
+};
+
+static int ml86v7667_init(struct ml86v7667_priv *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
+ int val;
+ int ret;
+
+ /* BT.656-4 output mode, register mode */
+ ret = ml86v7667_mask_set(client, MRA_REG,
+ MRA_OUTPUT_MODE_MASK | MRA_REGISTER_MODE,
+ MRA_ITUR_BT656 | MRA_REGISTER_MODE);
+
+ /* PLL circuit fixed clock, 32MHz */
+ ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,
+ PLLR1_FIXED_CLOCK);
+
+ /* ADC2 clamping voltage maximum */
+ ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,
+ ADC2_CLAMP_VOLTAGE(7));
+
+ /* enable luminance function */
+ ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,
+ SSEPL_LUMINANCE_ONOFF);
+
+ /* enable contrast function */
+ ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);
+
+ /*
+ * PAL/NTSC autodetection is enabled after reset,
+ * set the autodetected std in manual std mode and
+ * disable autodetection
+ */
+ val = i2c_smbus_read_byte_data(client, STATUS_REG);
+ if (val < 0)
+ return val;
+
+ priv->std = val & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
+ ret |= ml86v7667_mask_set(client, MRC_REG, MRC_AUTOSELECT, 0);
+
+ val = priv->std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
+ ret |= ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, val);
+
+ return ret;
+}
+
+static int ml86v7667_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ml86v7667_priv *priv;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&priv->sd, client, &ml86v7667_subdev_ops);
+
+ v4l2_ctrl_handler_init(&priv->hdl, 8);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -64, 63, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_CONTRAST, -8, 7, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_CHROMA_GAIN, -32, 31, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_RED_BALANCE, -4, 3, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, -4, 3, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+ V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+ priv->sd.ctrl_handler = &priv->hdl;
+
+ ret = priv->hdl.error;
+ if (ret)
+ goto cleanup;
+
+ v4l2_ctrl_handler_setup(&priv->hdl);
+
+ ret = ml86v7667_init(priv);
+ if (ret)
+ goto cleanup;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr, client->adapter->name);
+ return 0;
+
+cleanup:
+ v4l2_ctrl_handler_free(&priv->hdl);
+ v4l2_device_unregister_subdev(&priv->sd);
+ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
+ client->addr, client->adapter->name);
+ return ret;
+}
+
+static int ml86v7667_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ml86v7667_priv *priv = to_ml86v7667(sd);
+
+ v4l2_ctrl_handler_free(&priv->hdl);
+ v4l2_device_unregister_subdev(&priv->sd);
+
+ return 0;
+}
+
+static const struct i2c_device_id ml86v7667_id[] = {
+ {DRV_NAME, 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ml86v7667_id);
+
+static struct i2c_driver ml86v7667_i2c_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ml86v7667_probe,
+ .remove = ml86v7667_remove,
+ .id_table = ml86v7667_id,
+};
+
+module_i2c_driver(ml86v7667_i2c_driver);
+
+MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 54a9dd394f45..8190fec68080 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -570,15 +570,6 @@ static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
return 0;
}
-static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct msp_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->ident,
- (state->rev1 << 16) | state->rev2);
-}
-
static int msp_log_status(struct v4l2_subdev *sd)
{
struct msp_state *state = to_state(sd);
@@ -651,7 +642,6 @@ static const struct v4l2_ctrl_ops msp_ctrl_ops = {
static const struct v4l2_subdev_core_ops msp_core_ops = {
.log_status = msp_log_status,
- .g_chip_ident = msp_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -707,7 +697,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -ENODEV;
}
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
@@ -732,7 +722,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
v4l_dbg(1, msp_debug, client,
"not an msp3400 (cannot read chip version)\n");
- kfree(state);
return -ENODEV;
}
@@ -827,7 +816,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(state);
return err;
}
@@ -889,7 +877,6 @@ static int msp_remove(struct i2c_client *client)
msp_reset(client);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 8edb3d8f7b90..846b15f0bf64 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -554,10 +554,8 @@ static int mt9m032_g_register(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
int val;
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
val = mt9m032_read(client, reg->reg);
if (val < 0)
@@ -575,12 +573,9 @@ static int mt9m032_s_register(struct v4l2_subdev *sd,
struct mt9m032 *sensor = to_mt9m032(sd);
struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
return mt9m032_write(client, reg->reg, reg->val);
}
#endif
@@ -730,7 +725,7 @@ static int mt9m032_probe(struct i2c_client *client,
if (!client->dev.platform_data)
return -ENODEV;
- sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
if (sensor == NULL)
return -ENOMEM;
@@ -860,7 +855,6 @@ error_ctrl:
v4l2_ctrl_handler_free(&sensor->ctrls);
error_sensor:
mutex_destroy(&sensor->lock);
- kfree(sensor);
return ret;
}
@@ -873,7 +867,6 @@ static int mt9m032_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&sensor->ctrls);
media_entity_cleanup(&subdev->entity);
mutex_destroy(&sensor->lock);
- kfree(sensor);
return 0;
}
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 28cf95b37285..4734836fe5a4 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -16,18 +16,19 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
-#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/mt9p031.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
#include "aptina-pll.h"
@@ -124,9 +125,7 @@ struct mt9p031 {
int power_count;
struct clk *clk;
- struct regulator *vaa;
- struct regulator *vdd;
- struct regulator *vdd_io;
+ struct regulator_bulk_data regulators[3];
enum mt9p031_model model;
struct aptina_pll pll;
@@ -271,23 +270,26 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
static int mt9p031_power_on(struct mt9p031 *mt9p031)
{
+ int ret;
+
/* Ensure RESET_BAR is low */
- if (mt9p031->reset != -1) {
+ if (gpio_is_valid(mt9p031->reset)) {
gpio_set_value(mt9p031->reset, 0);
usleep_range(1000, 2000);
}
/* Bring up the supplies */
- regulator_enable(mt9p031->vdd);
- regulator_enable(mt9p031->vdd_io);
- regulator_enable(mt9p031->vaa);
+ ret = regulator_bulk_enable(ARRAY_SIZE(mt9p031->regulators),
+ mt9p031->regulators);
+ if (ret < 0)
+ return ret;
/* Emable clock */
if (mt9p031->clk)
clk_prepare_enable(mt9p031->clk);
/* Now RESET_BAR must be high */
- if (mt9p031->reset != -1) {
+ if (gpio_is_valid(mt9p031->reset)) {
gpio_set_value(mt9p031->reset, 1);
usleep_range(1000, 2000);
}
@@ -297,14 +299,13 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
static void mt9p031_power_off(struct mt9p031 *mt9p031)
{
- if (mt9p031->reset != -1) {
+ if (gpio_is_valid(mt9p031->reset)) {
gpio_set_value(mt9p031->reset, 0);
usleep_range(1000, 2000);
}
- regulator_disable(mt9p031->vaa);
- regulator_disable(mt9p031->vdd_io);
- regulator_disable(mt9p031->vdd);
+ regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
+ mt9p031->regulators);
if (mt9p031->clk)
clk_disable_unprepare(mt9p031->clk);
@@ -849,18 +850,18 @@ static int mt9p031_registered(struct v4l2_subdev *subdev)
/* Read out the chip version register */
data = mt9p031_read(client, MT9P031_CHIP_VERSION);
+ mt9p031_power_off(mt9p031);
+
if (data != MT9P031_CHIP_VERSION_VALUE) {
dev_err(&client->dev, "MT9P031 not detected, wrong version "
"0x%04x\n", data);
return -ENODEV;
}
- mt9p031_power_off(mt9p031);
-
dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
client->addr);
- return ret;
+ return 0;
}
static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
@@ -928,10 +929,36 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
* Driver initialization and probing
*/
+static struct mt9p031_platform_data *
+mt9p031_get_pdata(struct i2c_client *client)
+{
+ struct mt9p031_platform_data *pdata;
+ struct device_node *np;
+
+ if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+ return client->dev.platform_data;
+
+ np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ if (!np)
+ return NULL;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
+ of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
+ of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
+
+done:
+ of_node_put(np);
+ return pdata;
+}
+
static int mt9p031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
- struct mt9p031_platform_data *pdata = client->dev.platform_data;
+ struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct mt9p031 *mt9p031;
unsigned int i;
@@ -958,14 +985,14 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->model = did->driver_data;
mt9p031->reset = -1;
- mt9p031->vaa = devm_regulator_get(&client->dev, "vaa");
- mt9p031->vdd = devm_regulator_get(&client->dev, "vdd");
- mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io");
+ mt9p031->regulators[0].supply = "vdd";
+ mt9p031->regulators[1].supply = "vdd_io";
+ mt9p031->regulators[2].supply = "vaa";
- if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) ||
- IS_ERR(mt9p031->vdd_io)) {
+ ret = devm_regulator_bulk_get(&client->dev, 3, mt9p031->regulators);
+ if (ret < 0) {
dev_err(&client->dev, "Unable to get regulators\n");
- return -ENODEV;
+ return ret;
}
v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
@@ -1031,7 +1058,7 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->format.field = V4L2_FIELD_NONE;
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
- if (pdata->reset != -1) {
+ if (gpio_is_valid(pdata->reset)) {
ret = devm_gpio_request_one(&client->dev, pdata->reset,
GPIOF_OUT_INIT_LOW, "mt9p031_rst");
if (ret < 0)
@@ -1070,8 +1097,18 @@ static const struct i2c_device_id mt9p031_id[] = {
};
MODULE_DEVICE_TABLE(i2c, mt9p031_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt9p031_of_match[] = {
+ { .compatible = "aptina,mt9p031", },
+ { .compatible = "aptina,mt9p031m", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt9p031_of_match);
+#endif
+
static struct i2c_driver mt9p031_i2c_driver = {
.driver = {
+ .of_match_table = of_match_ptr(mt9p031_of_match),
.name = "mt9p031",
},
.probe = mt9p031_probe,
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index 2e189d8b71bb..796463466ef0 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -740,7 +740,7 @@ static int mt9t001_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- mt9t001 = kzalloc(sizeof(*mt9t001), GFP_KERNEL);
+ mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL);
if (!mt9t001)
return -ENOMEM;
@@ -801,7 +801,6 @@ done:
if (ret < 0) {
v4l2_ctrl_handler_free(&mt9t001->ctrls);
media_entity_cleanup(&mt9t001->subdev.entity);
- kfree(mt9t001);
}
return ret;
@@ -815,7 +814,6 @@ static int mt9t001_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&mt9t001->ctrls);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
- kfree(mt9t001);
return 0;
}
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 3f415fd12de3..f74698cf14c9 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <asm/div64.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/mt9v011.h>
@@ -407,13 +406,6 @@ static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
static int mt9v011_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
reg->val = mt9v011_read(sd, reg->reg & 0xff);
reg->size = 2;
@@ -423,31 +415,12 @@ static int mt9v011_g_register(struct v4l2_subdev *sd,
static int mt9v011_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff);
return 0;
}
#endif
-static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- u16 version;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011,
- version);
-}
-
static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9v011 *core =
@@ -489,7 +462,6 @@ static struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
.reset = mt9v011_reset,
- .g_chip_ident = mt9v011_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v011_g_register,
.s_register = mt9v011_s_register,
@@ -526,7 +498,7 @@ static int mt9v011_probe(struct i2c_client *c,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
- core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL);
+ core = devm_kzalloc(&c->dev, sizeof(struct mt9v011), GFP_KERNEL);
if (!core)
return -ENOMEM;
@@ -539,7 +511,6 @@ static int mt9v011_probe(struct i2c_client *c,
(version != MT9V011_REV_B_VERSION)) {
v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
version);
- kfree(core);
return -EINVAL;
}
@@ -562,7 +533,6 @@ static int mt9v011_probe(struct i2c_client *c,
v4l2_err(sd, "control initialization error %d\n", ret);
v4l2_ctrl_handler_free(&core->ctrls);
- kfree(core);
return ret;
}
core->sd.ctrl_handler = &core->ctrls;
@@ -598,7 +568,7 @@ static int mt9v011_remove(struct i2c_client *c)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&core->ctrls);
- kfree(to_mt9v011(sd));
+
return 0;
}
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 3f356cb28256..60c6f6739560 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -744,7 +744,7 @@ static int mt9v032_probe(struct i2c_client *client,
return -EIO;
}
- mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+ mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL);
if (!mt9v032)
return -ENOMEM;
@@ -830,8 +830,9 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+
if (ret < 0)
- kfree(mt9v032);
+ v4l2_ctrl_handler_free(&mt9v032->ctrls);
return ret;
}
@@ -841,9 +842,10 @@ static int mt9v032_remove(struct i2c_client *client)
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ v4l2_ctrl_handler_free(&mt9v032->ctrls);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
- kfree(mt9v032);
+
return 0;
}
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 8554b47f993a..271d0b7967a6 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -19,7 +19,6 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <media/noon010pc30.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/videodev2.h>
#include <linux/module.h>
#include <media/v4l2-ctrls.h>
@@ -712,7 +711,7 @@ static int noon010_probe(struct i2c_client *client,
return -EIO;
}
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -746,57 +745,50 @@ static int noon010_probe(struct i2c_client *client,
info->curr_win = &noon010_sizes[0];
if (gpio_is_valid(pdata->gpio_nreset)) {
- ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST");
+ ret = devm_gpio_request_one(&client->dev, pdata->gpio_nreset,
+ GPIOF_OUT_INIT_LOW,
+ "NOON010PC30 NRST");
if (ret) {
dev_err(&client->dev, "GPIO request error: %d\n", ret);
goto np_err;
}
info->gpio_nreset = pdata->gpio_nreset;
- gpio_direction_output(info->gpio_nreset, 0);
gpio_export(info->gpio_nreset, 0);
}
if (gpio_is_valid(pdata->gpio_nstby)) {
- ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY");
+ ret = devm_gpio_request_one(&client->dev, pdata->gpio_nstby,
+ GPIOF_OUT_INIT_LOW,
+ "NOON010PC30 NSTBY");
if (ret) {
dev_err(&client->dev, "GPIO request error: %d\n", ret);
- goto np_gpio_err;
+ goto np_err;
}
info->gpio_nstby = pdata->gpio_nstby;
- gpio_direction_output(info->gpio_nstby, 0);
gpio_export(info->gpio_nstby, 0);
}
for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
info->supply[i].supply = noon010_supply_name[i];
- ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
+ ret = devm_regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
info->supply);
if (ret)
- goto np_reg_err;
+ goto np_err;
info->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
if (ret < 0)
- goto np_me_err;
+ goto np_err;
ret = noon010_detect(client, info);
if (!ret)
return 0;
-np_me_err:
- regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
-np_reg_err:
- if (gpio_is_valid(info->gpio_nstby))
- gpio_free(info->gpio_nstby);
-np_gpio_err:
- if (gpio_is_valid(info->gpio_nreset))
- gpio_free(info->gpio_nreset);
np_err:
v4l2_ctrl_handler_free(&info->hdl);
v4l2_device_unregister_subdev(sd);
- kfree(info);
return ret;
}
@@ -807,17 +799,8 @@ static int noon010_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&info->hdl);
-
- regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
-
- if (gpio_is_valid(info->gpio_nreset))
- gpio_free(info->gpio_nreset);
-
- if (gpio_is_valid(info->gpio_nstby))
- gpio_free(info->gpio_nstby);
-
media_entity_cleanup(&sd->entity);
- kfree(info);
+
return 0;
}
diff --git a/drivers/media/i2c/ov7640.c b/drivers/media/i2c/ov7640.c
index b0cc927e8b19..faa64baf09e8 100644
--- a/drivers/media/i2c/ov7640.c
+++ b/drivers/media/i2c/ov7640.c
@@ -20,7 +20,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/slab.h>
MODULE_DESCRIPTION("OmniVision ov7640 sensor driver");
@@ -59,7 +58,7 @@ static int ov7640_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &ov7640_ops);
@@ -71,7 +70,6 @@ static int ov7640_probe(struct i2c_client *client,
if (write_regs(client, initial_registers) < 0) {
v4l_err(client, "error initializing OV7640\n");
- kfree(sd);
return -ENODEV;
}
@@ -84,7 +82,7 @@ static int ov7640_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
+
return 0;
}
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 617ad3fff4aa..e8a1ce204036 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -17,7 +17,6 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-mediabus.h>
#include <media/ov7670.h>
@@ -1462,25 +1461,12 @@ static const struct v4l2_ctrl_ops ov7670_ctrl_ops = {
.g_volatile_ctrl = ov7670_g_volatile_ctrl,
};
-static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
unsigned char val = 0;
int ret;
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
ret = ov7670_read(sd, reg->reg & 0xff, &val);
reg->val = val;
reg->size = 1;
@@ -1489,12 +1475,6 @@ static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
@@ -1503,7 +1483,6 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
- .g_chip_ident = ov7670_g_chip_ident,
.reset = ov7670_reset,
.init = ov7670_init,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1552,7 +1531,7 @@ static int ov7670_probe(struct i2c_client *client,
struct ov7670_info *info;
int ret;
- info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
sd = &info->sd;
@@ -1590,7 +1569,6 @@ static int ov7670_probe(struct i2c_client *client,
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",
@@ -1635,7 +1613,6 @@ static int ov7670_probe(struct i2c_client *client,
int err = info->hdl.error;
v4l2_ctrl_handler_free(&info->hdl);
- kfree(info);
return err;
}
/*
@@ -1659,7 +1636,6 @@ static int ov7670_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&info->hdl);
- kfree(info);
return 0;
}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 9eac5310942f..825ea86d982d 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1385,9 +1385,12 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
}
return 0;
err:
- for (++i; i < S5C73M3_MAX_SUPPLIES; i++)
- regulator_enable(state->supplies[i].consumer);
-
+ for (++i; i < S5C73M3_MAX_SUPPLIES; i++) {
+ int r = regulator_enable(state->supplies[i].consumer);
+ if (r < 0)
+ v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n",
+ state->supplies[i].supply, r);
+ }
return ret;
}
@@ -1511,59 +1514,40 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
.video = &s5c73m3_oif_video_ops,
};
-static int s5c73m3_configure_gpio(int nr, int val, const char *name)
-{
- unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- int ret;
-
- if (!gpio_is_valid(nr))
- return 0;
- ret = gpio_request_one(nr, flags, name);
- if (!ret)
- gpio_export(nr, 0);
- return ret;
-}
-
-static int s5c73m3_free_gpios(struct s5c73m3 *state)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(state->gpio); i++) {
- if (!gpio_is_valid(state->gpio[i].gpio))
- continue;
- gpio_free(state->gpio[i].gpio);
- state->gpio[i].gpio = -EINVAL;
- }
- return 0;
-}
-
static int s5c73m3_configure_gpios(struct s5c73m3 *state,
const struct s5c73m3_platform_data *pdata)
{
- const struct s5c73m3_gpio *gpio = &pdata->gpio_stby;
+ struct device *dev = &state->i2c_client->dev;
+ const struct s5c73m3_gpio *gpio;
+ unsigned long flags;
int ret;
state->gpio[STBY].gpio = -EINVAL;
state->gpio[RST].gpio = -EINVAL;
- ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY");
- if (ret) {
- s5c73m3_free_gpios(state);
- return ret;
+ gpio = &pdata->gpio_stby;
+ if (gpio_is_valid(gpio->gpio)) {
+ flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+ | GPIOF_EXPORT;
+ ret = devm_gpio_request_one(dev, gpio->gpio, flags,
+ "S5C73M3_STBY");
+ if (ret < 0)
+ return ret;
+
+ state->gpio[STBY] = *gpio;
}
- state->gpio[STBY] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
gpio = &pdata->gpio_reset;
- ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST");
- if (ret) {
- s5c73m3_free_gpios(state);
- return ret;
+ if (gpio_is_valid(gpio->gpio)) {
+ flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+ | GPIOF_EXPORT;
+ ret = devm_gpio_request_one(dev, gpio->gpio, flags,
+ "S5C73M3_RST");
+ if (ret < 0)
+ return ret;
+
+ state->gpio[RST] = *gpio;
}
- state->gpio[RST] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
return 0;
}
@@ -1626,10 +1610,11 @@ static int s5c73m3_probe(struct i2c_client *client,
state->mclk_frequency = pdata->mclk_frequency;
state->bus_type = pdata->bus_type;
+ state->i2c_client = client;
ret = s5c73m3_configure_gpios(state, pdata);
if (ret)
- goto out_err1;
+ goto out_err;
for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++)
state->supplies[i].supply = s5c73m3_supply_names[i];
@@ -1638,12 +1623,12 @@ static int s5c73m3_probe(struct i2c_client *client,
state->supplies);
if (ret) {
dev_err(dev, "failed to get regulators\n");
- goto out_err2;
+ goto out_err;
}
ret = s5c73m3_init_controls(state);
if (ret)
- goto out_err2;
+ goto out_err;
state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1];
state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1];
@@ -1659,16 +1644,12 @@ static int s5c73m3_probe(struct i2c_client *client,
ret = s5c73m3_register_spi_driver(state);
if (ret < 0)
- goto out_err2;
-
- state->i2c_client = client;
+ goto out_err;
v4l2_info(sd, "%s: completed succesfully\n", __func__);
return 0;
-out_err2:
- s5c73m3_free_gpios(state);
-out_err1:
+out_err:
media_entity_cleanup(&sd->entity);
return ret;
}
@@ -1688,7 +1669,6 @@ static int s5c73m3_remove(struct i2c_client *client)
media_entity_cleanup(&sensor_sd->entity);
s5c73m3_unregister_spi_driver(state);
- s5c73m3_free_gpios(state);
return 0;
}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
index 6f3a9c00fe65..8079e26eb5e2 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -73,7 +73,7 @@ int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
memset(padding, 0, sizeof(padding));
- for (i = 0; i < count ; i++) {
+ for (i = 0; i < count; i++) {
r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX);
if (r < 0)
return r;
@@ -98,7 +98,7 @@ int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
unsigned int i, j = 0;
int r = 0;
- for (i = 0; i < count ; i++) {
+ for (i = 0; i < count; i++) {
r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX);
if (r < 0)
return r;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index bdf5e3db31d1..789c02a6ca1a 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -1491,58 +1491,41 @@ static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
/*
* GPIO setup
*/
-static int s5k6aa_configure_gpio(int nr, int val, const char *name)
-{
- unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- int ret;
-
- if (!gpio_is_valid(nr))
- return 0;
- ret = gpio_request_one(nr, flags, name);
- if (!ret)
- gpio_export(nr, 0);
- return ret;
-}
-
-static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) {
- if (!gpio_is_valid(s5k6aa->gpio[i].gpio))
- continue;
- gpio_free(s5k6aa->gpio[i].gpio);
- s5k6aa->gpio[i].gpio = -EINVAL;
- }
-}
static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
const struct s5k6aa_platform_data *pdata)
{
- const struct s5k6aa_gpio *gpio = &pdata->gpio_stby;
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ const struct s5k6aa_gpio *gpio;
+ unsigned long flags;
int ret;
s5k6aa->gpio[STBY].gpio = -EINVAL;
s5k6aa->gpio[RST].gpio = -EINVAL;
- ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY");
- if (ret) {
- s5k6aa_free_gpios(s5k6aa);
- return ret;
+ gpio = &pdata->gpio_stby;
+ if (gpio_is_valid(gpio->gpio)) {
+ flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+ | GPIOF_EXPORT;
+ ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
+ "S5K6AA_STBY");
+ if (ret < 0)
+ return ret;
+
+ s5k6aa->gpio[STBY] = *gpio;
}
- s5k6aa->gpio[STBY] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
gpio = &pdata->gpio_reset;
- ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST");
- if (ret) {
- s5k6aa_free_gpios(s5k6aa);
- return ret;
+ if (gpio_is_valid(gpio->gpio)) {
+ flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+ | GPIOF_EXPORT;
+ ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
+ "S5K6AA_RST");
+ if (ret < 0)
+ return ret;
+
+ s5k6aa->gpio[RST] = *gpio;
}
- s5k6aa->gpio[RST] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
return 0;
}
@@ -1593,7 +1576,7 @@ static int s5k6aa_probe(struct i2c_client *client,
ret = s5k6aa_configure_gpios(s5k6aa, pdata);
if (ret)
- goto out_err2;
+ goto out_err;
for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
@@ -1602,12 +1585,12 @@ static int s5k6aa_probe(struct i2c_client *client,
s5k6aa->supplies);
if (ret) {
dev_err(&client->dev, "Failed to get regulators\n");
- goto out_err3;
+ goto out_err;
}
ret = s5k6aa_initialize_ctrls(s5k6aa);
if (ret)
- goto out_err3;
+ goto out_err;
s5k6aa_presets_data_init(s5k6aa);
@@ -1618,9 +1601,7 @@ static int s5k6aa_probe(struct i2c_client *client,
return 0;
-out_err3:
- s5k6aa_free_gpios(s5k6aa);
-out_err2:
+out_err:
media_entity_cleanup(&s5k6aa->sd.entity);
return ret;
}
@@ -1628,12 +1609,10 @@ out_err2:
static int s5k6aa_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
media_entity_cleanup(&sd->entity);
- s5k6aa_free_gpios(s5k6aa);
return 0;
}
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
index b4e1ccbd87ec..70bc72e795d0 100644
--- a/drivers/media/i2c/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
@@ -33,7 +33,6 @@
#include <media/saa6588.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
/* insmod options */
@@ -443,17 +442,9 @@ static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
return 0;
}
-static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops saa6588_core_ops = {
- .g_chip_ident = saa6588_g_chip_ident,
.ioctl = saa6588_ioctl,
};
@@ -478,17 +469,15 @@ static int saa6588_probe(struct i2c_client *client,
v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- s = kzalloc(sizeof(*s), GFP_KERNEL);
+ s = devm_kzalloc(&client->dev, sizeof(*s), GFP_KERNEL);
if (s == NULL)
return -ENOMEM;
s->buf_size = bufblocks * 3;
- s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
- if (s->buffer == NULL) {
- kfree(s);
+ s->buffer = devm_kzalloc(&client->dev, s->buf_size, GFP_KERNEL);
+ if (s->buffer == NULL)
return -ENOMEM;
- }
sd = &s->sd;
v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
spin_lock_init(&s->lock);
@@ -516,8 +505,6 @@ static int saa6588_remove(struct i2c_client *client)
cancel_delayed_work_sync(&s->work);
- kfree(s->buffer);
- kfree(s);
return 0;
}
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
index 51cd4c8f0520..ac43e929a1d6 100644
--- a/drivers/media/i2c/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
@@ -35,7 +35,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
@@ -203,7 +202,7 @@ static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
status = saa7110_read(sd);
if (status & 0x40) {
v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
- return decoder->norm; /* no change*/
+ return V4L2_STD_UNKNOWN;
}
if ((status & 3) == 0) {
saa7110_write(sd, 0x06, 0x83);
@@ -265,7 +264,7 @@ static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
- *(v4l2_std_id *)std = determine_norm(sd);
+ *std &= determine_norm(sd);
return 0;
}
@@ -352,13 +351,6 @@ static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
@@ -366,7 +358,6 @@ static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
};
static const struct v4l2_subdev_core_ops saa7110_core_ops = {
- .g_chip_ident = saa7110_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -406,7 +397,7 @@ static int saa7110_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
sd = &decoder->sd;
@@ -428,7 +419,6 @@ static int saa7110_probe(struct i2c_client *client,
int err = decoder->hdl.error;
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return err;
}
v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -469,7 +459,6 @@ static int saa7110_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return 0;
}
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 52c717d977c9..7fd766ec64c8 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -46,7 +46,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <media/saa7115.h>
#include <asm/div64.h>
@@ -63,6 +62,16 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
+enum saa711x_model {
+ SAA7111A,
+ SAA7111,
+ SAA7113,
+ GM7113C,
+ SAA7114,
+ SAA7115,
+ SAA7118,
+};
+
struct saa711x_state {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
@@ -80,7 +89,7 @@ struct saa711x_state {
int radio;
int width;
int height;
- u32 ident;
+ enum saa711x_model ident;
u32 audclk_freq;
u32 crystal_freq;
bool ucgc;
@@ -111,10 +120,10 @@ static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
/* Sanity routine to check if a register is present */
static int saa711x_has_reg(const int id, const u8 reg)
{
- if (id == V4L2_IDENT_SAA7111)
+ if (id == SAA7111)
return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
(reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
- if (id == V4L2_IDENT_SAA7111A)
+ if (id == SAA7111A)
return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
reg != 0x14 && reg != 0x18 && reg != 0x19 &&
reg != 0x1d && reg != 0x1e;
@@ -127,16 +136,18 @@ static int saa711x_has_reg(const int id, const u8 reg)
return 0;
switch (id) {
- case V4L2_IDENT_SAA7113:
+ case GM7113C:
+ return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && reg < 0x20;
+ case SAA7113:
return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
reg != 0x5d && reg < 0x63;
- case V4L2_IDENT_SAA7114:
+ case SAA7114:
return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
(reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
reg != 0x81 && reg < 0xf0;
- case V4L2_IDENT_SAA7115:
+ case SAA7115:
return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
- case V4L2_IDENT_SAA7118:
+ case SAA7118:
return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
(reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
(reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
@@ -214,7 +225,10 @@ static const unsigned char saa7111_init[] = {
0x00, 0x00
};
-/* SAA7113 init codes */
+/* SAA7113/GM7113C init codes
+ * It's important that R_14... R_17 == 0x00
+ * for the gm7113c chip to deliver stable video
+ */
static const unsigned char saa7113_init[] = {
R_01_INC_DELAY, 0x08,
R_02_INPUT_CNTL_1, 0xc2,
@@ -448,6 +462,24 @@ static const unsigned char saa7115_cfg_50hz_video[] = {
/* ============== SAA7715 VIDEO templates (end) ======= */
+/* ============== GM7113C VIDEO templates ============= */
+static const unsigned char gm7113c_cfg_60hz_video[] = {
+ R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
+ R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
+
+ 0x00, 0x00
+};
+
+static const unsigned char gm7113c_cfg_50hz_video[] = {
+ R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
+ R_0E_CHROMA_CNTL_1, 0x07,
+
+ 0x00, 0x00
+};
+
+/* ============== GM7113C VIDEO templates (end) ======= */
+
+
static const unsigned char saa7115_cfg_vbi_on[] = {
R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
@@ -932,11 +964,17 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
if (std & V4L2_STD_525_60) {
v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
- saa711x_writeregs(sd, saa7115_cfg_60hz_video);
+ if (state->ident == GM7113C)
+ saa711x_writeregs(sd, gm7113c_cfg_60hz_video);
+ else
+ saa711x_writeregs(sd, saa7115_cfg_60hz_video);
saa711x_set_size(sd, 720, 480);
} else {
v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
- saa711x_writeregs(sd, saa7115_cfg_50hz_video);
+ if (state->ident == GM7113C)
+ saa711x_writeregs(sd, gm7113c_cfg_50hz_video);
+ else
+ saa711x_writeregs(sd, saa7115_cfg_50hz_video);
saa711x_set_size(sd, 720, 576);
}
@@ -949,7 +987,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
011 NTSC N (3.58MHz) PAL M (3.58MHz)
100 reserved NTSC-Japan (3.58MHz)
*/
- if (state->ident <= V4L2_IDENT_SAA7113) {
+ if (state->ident <= SAA7113 ||
+ state->ident == GM7113C) {
u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
if (std == V4L2_STD_PAL_M) {
@@ -968,9 +1007,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
/* restart task B if needed */
int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
- if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+ if (taskb && state->ident == SAA7114)
saa711x_writeregs(sd, saa7115_cfg_vbi_on);
- }
/* switch audio mode too! */
saa711x_s_clock_freq(sd, state->audclk_freq);
@@ -992,7 +1030,7 @@ static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_forma
#else
/* SAA7113 and SAA7118 also should support VBI - Need testing */
- if (state->ident != V4L2_IDENT_SAA7115)
+ if (state->ident != SAA7115)
return;
#endif
@@ -1214,13 +1252,14 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct saa711x_state *state = to_state(sd);
- u8 mask = (state->ident <= V4L2_IDENT_SAA7111A) ? 0xf8 : 0xf0;
+ u8 mask = (state->ident <= SAA7111A) ? 0xf8 : 0xf0;
v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n",
input, output);
/* saa7111/3 does not have these inputs */
- if (state->ident <= V4L2_IDENT_SAA7113 &&
+ if ((state->ident <= SAA7113 ||
+ state->ident == GM7113C) &&
(input == SAA7115_COMPOSITE4 ||
input == SAA7115_COMPOSITE5)) {
return -EINVAL;
@@ -1235,7 +1274,7 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
state->input = input;
/* saa7111 has slightly different input numbering */
- if (state->ident <= V4L2_IDENT_SAA7111A) {
+ if (state->ident <= SAA7111A) {
if (input >= SAA7115_COMPOSITE4)
input -= 2;
/* saa7111 specific */
@@ -1258,13 +1297,13 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
state->output = output;
- if (state->ident == V4L2_IDENT_SAA7114 ||
- state->ident == V4L2_IDENT_SAA7115) {
+ if (state->ident == SAA7114 ||
+ state->ident == SAA7115) {
saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
(saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
(state->output & 0x01));
}
- if (state->ident > V4L2_IDENT_SAA7111A) {
+ if (state->ident > SAA7111A) {
if (config & SAA7115_IDQ_IS_DEFAULT)
saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20);
else
@@ -1277,7 +1316,7 @@ static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
{
struct saa711x_state *state = to_state(sd);
- if (state->ident > V4L2_IDENT_SAA7111A)
+ if (state->ident > SAA7111A)
return -EINVAL;
saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
(val ? 0x80 : 0));
@@ -1367,7 +1406,7 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
- if (state->ident == V4L2_IDENT_SAA7115) {
+ if (state->ident == SAA7115) {
reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
@@ -1389,6 +1428,7 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
*std &= V4L2_STD_SECAM;
break;
default:
+ *std = V4L2_STD_UNKNOWN;
/* Can't detect anything */
break;
}
@@ -1397,8 +1437,10 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
/* horizontal/vertical not locked */
- if (reg1f & 0x40)
+ if (reg1f & 0x40) {
+ *std = V4L2_STD_UNKNOWN;
goto ret;
+ }
if (reg1f & 0x20)
*std &= V4L2_STD_525_60;
@@ -1418,7 +1460,7 @@ static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
int reg1f;
*status = V4L2_IN_ST_NO_SIGNAL;
- if (state->ident == V4L2_IDENT_SAA7115)
+ if (state->ident == SAA7115)
reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
@@ -1429,12 +1471,6 @@ static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = saa711x_read(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -1442,25 +1478,11 @@ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
#endif
-static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct saa711x_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
-}
-
static int saa711x_log_status(struct v4l2_subdev *sd)
{
struct saa711x_state *state = to_state(sd);
@@ -1469,7 +1491,7 @@ static int saa711x_log_status(struct v4l2_subdev *sd)
int vcr;
v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
- if (state->ident != V4L2_IDENT_SAA7115) {
+ if (state->ident != SAA7115) {
/* status for the saa7114 */
reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
signalOk = (reg1f & 0xc1) == 0x81;
@@ -1520,7 +1542,6 @@ static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
static const struct v4l2_subdev_core_ops saa711x_core_ops = {
.log_status = saa711x_log_status,
- .g_chip_ident = saa711x_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1571,55 +1592,145 @@ static const struct v4l2_subdev_ops saa711x_ops = {
.vbi = &saa711x_vbi_ops,
};
+#define CHIP_VER_SIZE 16
+
/* ----------------------------------------------------------------------- */
-static int saa711x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+/**
+ * saa711x_detect_chip - Detects the saa711x (or clone) variant
+ * @client: I2C client structure.
+ * @id: I2C device ID structure.
+ * @name: Name of the device to be filled.
+ *
+ * Detects the Philips/NXP saa711x chip, or some clone of it.
+ * if 'id' is NULL or id->driver_data is equal to 1, it auto-probes
+ * the analog demod.
+ * If the tuner is not found, it returns -ENODEV.
+ * If auto-detection is disabled and the tuner doesn't match what it was
+ * requred, it returns -EINVAL and fills 'name'.
+ * If the chip is found, it returns the chip ID and fills 'name'.
+ */
+static int saa711x_detect_chip(struct i2c_client *client,
+ const struct i2c_device_id *id,
+ char *name)
{
- struct saa711x_state *state;
- struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
- int i;
- char name[17];
+ char chip_ver[CHIP_VER_SIZE];
char chip_id;
- int autodetect = !id || id->driver_data == 1;
+ int i;
+ int autodetect;
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
+ autodetect = !id || id->driver_data == 1;
- for (i = 0; i < 0x0f; i++) {
+ /* Read the chip version register */
+ for (i = 0; i < CHIP_VER_SIZE; i++) {
i2c_smbus_write_byte_data(client, 0, i);
- name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
+ chip_ver[i] = i2c_smbus_read_byte_data(client, 0);
+ name[i] = (chip_ver[i] & 0x0f) + '0';
if (name[i] > '9')
name[i] += 'a' - '9' - 1;
}
name[i] = '\0';
- chip_id = name[5];
+ /* Check if it is a Philips/NXP chip */
+ if (!memcmp(name + 1, "f711", 4)) {
+ chip_id = name[5];
+ snprintf(name, CHIP_VER_SIZE, "saa711%c", chip_id);
- /* Check whether this chip is part of the saa711x series */
- if (memcmp(name + 1, "f711", 4)) {
- v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
- client->addr << 1, name);
- return -ENODEV;
+ if (!autodetect && strcmp(name, id->name))
+ return -EINVAL;
+
+ switch (chip_id) {
+ case '1':
+ if (chip_ver[0] & 0xf0) {
+ snprintf(name, CHIP_VER_SIZE, "saa711%ca", chip_id);
+ v4l_info(client, "saa7111a variant found\n");
+ return SAA7111A;
+ }
+ return SAA7111;
+ case '3':
+ return SAA7113;
+ case '4':
+ return SAA7114;
+ case '5':
+ return SAA7115;
+ case '8':
+ return SAA7118;
+ default:
+ v4l2_info(client,
+ "WARNING: Philips/NXP chip unknown - Falling back to saa7111\n");
+ return SAA7111;
+ }
}
- /* Safety check */
- if (!autodetect && id->name[6] != chip_id) {
- v4l_warn(client, "found saa711%c while %s was expected\n",
- chip_id, id->name);
+ /* Check if it is a gm7113c */
+ if (!memcmp(name, "0000", 4)) {
+ chip_id = 0;
+ for (i = 0; i < 4; i++) {
+ chip_id = chip_id << 1;
+ chip_id |= (chip_ver[i] & 0x80) ? 1 : 0;
+ }
+
+ /*
+ * Note: From the datasheet, only versions 1 and 2
+ * exists. However, tests on a device labeled as:
+ * "GM7113C 1145" returned "10" on all 16 chip
+ * version (reg 0x00) reads. So, we need to also
+ * accept at least verion 0. For now, let's just
+ * assume that a device that returns "0000" for
+ * the lower nibble is a gm7113c.
+ */
+
+ strlcpy(name, "gm7113c", CHIP_VER_SIZE);
+
+ if (!autodetect && strcmp(name, id->name))
+ return -EINVAL;
+
+ v4l_dbg(1, debug, client,
+ "It seems to be a %s chip (%*ph) @ 0x%x.\n",
+ name, 16, chip_ver, client->addr << 1);
+
+ return GM7113C;
}
- snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
- v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
- client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
+ /* Chip was not discovered. Return its ID and don't bind */
+ v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n",
+ 16, chip_ver, client->addr << 1);
+ return -ENODEV;
+}
+
+static int saa711x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct saa711x_state *state;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+ int ident;
+ char name[CHIP_VER_SIZE + 1];
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ ident = saa711x_detect_chip(client, id, name);
+ if (ident == -EINVAL) {
+ /* Chip exists, but doesn't match */
+ v4l_warn(client, "found %s while %s was expected\n",
+ name, id->name);
+ return -ENODEV;
+ }
+ if (ident < 0)
+ return ident;
+
+ strlcpy(client->name, name, sizeof(client->name));
+
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
+ v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+ client->addr << 1, client->adapter->name);
hdl = &state->hdl;
v4l2_ctrl_handler_init(hdl, 6);
/* add in ascending ID order */
@@ -1640,7 +1751,6 @@ static int saa711x_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(state);
return err;
}
v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
@@ -1649,31 +1759,7 @@ static int saa711x_probe(struct i2c_client *client,
state->output = SAA7115_IPORT_ON;
state->enable = 1;
state->radio = 0;
- switch (chip_id) {
- case '1':
- state->ident = V4L2_IDENT_SAA7111;
- if (saa711x_read(sd, R_00_CHIP_VERSION) & 0xf0) {
- v4l_info(client, "saa7111a variant found\n");
- state->ident = V4L2_IDENT_SAA7111A;
- }
- break;
- case '3':
- state->ident = V4L2_IDENT_SAA7113;
- break;
- case '4':
- state->ident = V4L2_IDENT_SAA7114;
- break;
- case '5':
- state->ident = V4L2_IDENT_SAA7115;
- break;
- case '8':
- state->ident = V4L2_IDENT_SAA7118;
- break;
- default:
- state->ident = V4L2_IDENT_SAA7111;
- v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
- break;
- }
+ state->ident = ident;
state->audclk_freq = 48000;
@@ -1682,18 +1768,19 @@ static int saa711x_probe(struct i2c_client *client,
/* init to 60hz/48khz */
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
switch (state->ident) {
- case V4L2_IDENT_SAA7111:
- case V4L2_IDENT_SAA7111A:
+ case SAA7111:
+ case SAA7111A:
saa711x_writeregs(sd, saa7111_init);
break;
- case V4L2_IDENT_SAA7113:
+ case GM7113C:
+ case SAA7113:
saa711x_writeregs(sd, saa7113_init);
break;
default:
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa711x_writeregs(sd, saa7115_init_auto_input);
}
- if (state->ident > V4L2_IDENT_SAA7111A)
+ if (state->ident > SAA7111A)
saa711x_writeregs(sd, saa7115_init_misc);
saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
v4l2_ctrl_handler_setup(hdl);
@@ -1712,7 +1799,6 @@ static int saa711x_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- kfree(to_state(sd));
return 0;
}
@@ -1723,6 +1809,7 @@ static const struct i2c_device_id saa711x_id[] = {
{ "saa7114", 0 },
{ "saa7115", 0 },
{ "saa7118", 0 },
+ { "gm7113c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, saa711x_id);
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
index 8a47ac10927f..264b755bedce 100644
--- a/drivers/media/i2c/saa7127.c
+++ b/drivers/media/i2c/saa7127.c
@@ -54,7 +54,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/saa7127.h>
static int debug;
@@ -251,10 +250,15 @@ static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
**********************************************************************
*/
+enum saa712x_model {
+ SAA7127,
+ SAA7129,
+};
+
struct saa7127_state {
struct v4l2_subdev sd;
v4l2_std_id std;
- u32 ident;
+ enum saa712x_model ident;
enum saa7127_input_type input_type;
enum saa7127_output_type output_type;
int video_enable;
@@ -482,7 +486,7 @@ static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
inittab = saa7127_init_config_60hz;
state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
- } else if (state->ident == V4L2_IDENT_SAA7129 &&
+ } else if (state->ident == SAA7129 &&
(std & V4L2_STD_SECAM) &&
!(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
@@ -517,7 +521,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
break;
case SAA7127_OUTPUT_TYPE_COMPOSITE:
- if (state->ident == V4L2_IDENT_SAA7129)
+ if (state->ident == SAA7129)
state->reg_2d = 0x20; /* CVBS only */
else
state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
@@ -525,7 +529,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
break;
case SAA7127_OUTPUT_TYPE_SVIDEO:
- if (state->ident == V4L2_IDENT_SAA7129)
+ if (state->ident == SAA7129)
state->reg_2d = 0x18; /* Y + C */
else
state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */
@@ -543,7 +547,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
break;
case SAA7127_OUTPUT_TYPE_BOTH:
- if (state->ident == V4L2_IDENT_SAA7129)
+ if (state->ident == SAA7129)
state->reg_2d = 0x38;
else
state->reg_2d = 0xbf;
@@ -661,12 +665,6 @@ static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_v
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = saa7127_read(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -674,25 +672,11 @@ static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
#endif
-static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct saa7127_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
-}
-
static int saa7127_log_status(struct v4l2_subdev *sd)
{
struct saa7127_state *state = to_state(sd);
@@ -712,7 +696,6 @@ static int saa7127_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops saa7127_core_ops = {
.log_status = saa7127_log_status,
- .g_chip_ident = saa7127_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = saa7127_g_register,
.s_register = saa7127_s_register,
@@ -752,7 +735,7 @@ static int saa7127_probe(struct i2c_client *client,
v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
client->addr << 1);
- state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -767,7 +750,6 @@ static int saa7127_probe(struct i2c_client *client,
if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
(saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
v4l2_dbg(1, debug, sd, "saa7127 not found\n");
- kfree(state);
return -ENODEV;
}
@@ -782,10 +764,10 @@ static int saa7127_probe(struct i2c_client *client,
if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
read_result);
- state->ident = V4L2_IDENT_SAA7129;
+ state->ident = SAA7129;
strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
} else {
- state->ident = V4L2_IDENT_SAA7127;
+ state->ident = SAA7127;
strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
}
}
@@ -809,7 +791,7 @@ static int saa7127_probe(struct i2c_client *client,
saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
saa7127_set_video_enable(sd, 1);
- if (state->ident == V4L2_IDENT_SAA7129)
+ if (state->ident == SAA7129)
saa7127_write_inittab(sd, saa7129_init_config_extra);
return 0;
}
@@ -823,7 +805,6 @@ static int saa7127_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
/* Turn off TV output */
saa7127_set_video_enable(sd, 0);
- kfree(to_state(sd));
return 0;
}
@@ -831,10 +812,10 @@ static int saa7127_remove(struct i2c_client *client)
static struct i2c_device_id saa7127_id[] = {
{ "saa7127_auto", 0 }, /* auto-detection */
- { "saa7126", V4L2_IDENT_SAA7127 },
- { "saa7127", V4L2_IDENT_SAA7127 },
- { "saa7128", V4L2_IDENT_SAA7129 },
- { "saa7129", V4L2_IDENT_SAA7129 },
+ { "saa7126", SAA7127 },
+ { "saa7127", SAA7127 },
+ { "saa7128", SAA7129 },
+ { "saa7129", SAA7129 },
{ }
};
MODULE_DEVICE_TABLE(i2c, saa7127_id);
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index cf3a0aa7e45e..401ca114ab99 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -977,12 +977,6 @@ static int saa717x_s_video_routing(struct v4l2_subdev *sd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = saa717x_read(sd, reg->reg);
reg->size = 1;
return 0;
@@ -990,14 +984,9 @@ static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
u16 addr = reg->reg & 0xffff;
u8 val = reg->val & 0xff;
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
saa717x_write(sd, addr, val);
return 0;
}
@@ -1262,7 +1251,7 @@ static int saa717x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (decoder == NULL)
return -ENOMEM;
@@ -1276,7 +1265,6 @@ static int saa717x_probe(struct i2c_client *client,
id = saa717x_read(sd, 0x5a0);
if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
- kfree(decoder);
return -ENODEV;
}
if (id == 0xc2)
@@ -1316,7 +1304,6 @@ static int saa717x_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(decoder);
return err;
}
@@ -1353,7 +1340,6 @@ static int saa717x_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/saa7185.c b/drivers/media/i2c/saa7185.c
index 2c6b65c76e2b..f56c1c88b27d 100644
--- a/drivers/media/i2c/saa7185.c
+++ b/drivers/media/i2c/saa7185.c
@@ -32,7 +32,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
@@ -285,17 +284,9 @@ static int saa7185_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops saa7185_core_ops = {
- .g_chip_ident = saa7185_g_chip_ident,
.init = saa7185_init,
};
@@ -326,7 +317,7 @@ static int saa7185_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
+ encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
encoder->norm = V4L2_STD_NTSC;
@@ -352,7 +343,6 @@ static int saa7185_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
/* SW: output off is active */
saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
- kfree(encoder);
return 0;
}
diff --git a/drivers/media/i2c/saa7191.c b/drivers/media/i2c/saa7191.c
index d7d1670e0ca3..606a4baf944d 100644
--- a/drivers/media/i2c/saa7191.c
+++ b/drivers/media/i2c/saa7191.c
@@ -22,7 +22,6 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include "saa7191.h"
@@ -272,7 +271,7 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
dprintk("SAA7191 extended signal auto-detection...\n");
- *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+ *norm &= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
stdc &= ~SAA7191_STDC_SECS;
ctl3 &= ~(SAA7191_CTL3_FSEL);
@@ -303,7 +302,7 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
if (status & SAA7191_STATUS_FIDT) {
/* 60Hz signal -> NTSC */
dprintk("60Hz signal: NTSC\n");
- *norm = V4L2_STD_NTSC;
+ *norm &= V4L2_STD_NTSC;
return 0;
}
@@ -325,12 +324,13 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
if (status & SAA7191_STATUS_FIDT) {
dprintk("No 50Hz signal\n");
saa7191_s_std(sd, old_norm);
- return -EAGAIN;
+ *norm = V4L2_STD_UNKNOWN;
+ return 0;
}
if (status & SAA7191_STATUS_CODE) {
dprintk("PAL\n");
- *norm = V4L2_STD_PAL;
+ *norm &= V4L2_STD_PAL;
return saa7191_s_std(sd, old_norm);
}
@@ -350,18 +350,19 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
/* not 50Hz ? */
if (status & SAA7191_STATUS_FIDT) {
dprintk("No 50Hz signal\n");
- err = -EAGAIN;
+ *norm = V4L2_STD_UNKNOWN;
goto out;
}
if (status & SAA7191_STATUS_CODE) {
/* Color detected -> SECAM */
dprintk("SECAM\n");
- *norm = V4L2_STD_SECAM;
+ *norm &= V4L2_STD_SECAM;
return saa7191_s_std(sd, old_norm);
}
dprintk("No color detected with SECAM - Going back to PAL.\n");
+ *norm = V4L2_STD_UNKNOWN;
out:
return saa7191_s_std(sd, old_norm);
@@ -567,18 +568,9 @@ static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
-static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops saa7191_core_ops = {
- .g_chip_ident = saa7191_g_chip_ident,
.g_ctrl = saa7191_g_ctrl,
.s_ctrl = saa7191_s_ctrl,
.s_std = saa7191_s_std,
@@ -605,7 +597,7 @@ static int saa7191_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
@@ -615,7 +607,6 @@ static int saa7191_probe(struct i2c_client *client,
err = saa7191_write_block(sd, sizeof(initseq), initseq);
if (err) {
printk(KERN_ERR "SAA7191 initialization failed\n");
- kfree(decoder);
return err;
}
@@ -636,7 +627,6 @@ static int saa7191_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_saa7191(sd));
return 0;
}
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index cae4f4683851..7ac7580f85c9 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -2383,8 +2383,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
- if (gpio_request_one(sensor->platform_data->xshutdown, 0,
- "SMIA++ xshutdown") != 0) {
+ if (devm_gpio_request_one(&client->dev,
+ sensor->platform_data->xshutdown, 0,
+ "SMIA++ xshutdown") != 0) {
dev_err(&client->dev,
"unable to acquire reset gpio %d\n",
sensor->platform_data->xshutdown);
@@ -2393,10 +2394,8 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
rval = smiapp_power_on(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_smiapp_power_on;
- }
+ if (rval)
+ return -ENODEV;
rval = smiapp_identify_module(subdev);
if (rval) {
@@ -2656,11 +2655,6 @@ out_ident_release:
out_power_off:
smiapp_power_off(sensor);
-
-out_smiapp_power_on:
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_free(sensor->platform_data->xshutdown);
-
return rval;
}
@@ -2854,12 +2848,10 @@ static int smiapp_remove(struct i2c_client *client)
device_remove_file(&client->dev, &dev_attr_nvm);
for (i = 0; i < sensor->ssds_used; i++) {
- media_entity_cleanup(&sensor->ssds[i].sd.entity);
v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+ media_entity_cleanup(&sensor->ssds[i].sd.entity);
}
smiapp_free_controls(sensor);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_free(sensor->platform_data->xshutdown);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
index a2a5cbbdbe28..1d384a371b41 100644
--- a/drivers/media/i2c/soc_camera/imx074.c
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -18,8 +18,9 @@
#include <linux/module.h>
#include <media/soc_camera.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
/* IMX074 registers */
@@ -77,6 +78,7 @@ struct imx074_datafmt {
struct imx074 {
struct v4l2_subdev subdev;
const struct imx074_datafmt *fmt;
+ struct v4l2_clk *clk;
};
static const struct imx074_datafmt imx074_colour_fmts[] = {
@@ -251,29 +253,13 @@ static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
return reg_write(client, MODE_SELECT, !!enable);
}
-static int imx074_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_IMX074;
- id->revision = 0;
-
- return 0;
-}
-
static int imx074_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct imx074 *priv = to_imx074(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
static int imx074_g_mbus_config(struct v4l2_subdev *sd,
@@ -299,7 +285,6 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
};
static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
- .g_chip_ident = imx074_g_chip_ident,
.s_power = imx074_s_power,
};
@@ -431,6 +416,7 @@ static int imx074_probe(struct i2c_client *client,
struct imx074 *priv;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ int ret;
if (!ssdd) {
dev_err(&client->dev, "IMX074: missing platform data!\n");
@@ -451,12 +437,35 @@ static int imx074_probe(struct i2c_client *client,
priv->fmt = &imx074_colour_fmts[0];
- return imx074_video_probe(client);
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ dev_info(&client->dev, "Error %ld getting clock\n", PTR_ERR(priv->clk));
+ return -EPROBE_DEFER;
+ }
+
+ ret = soc_camera_power_init(&client->dev, ssdd);
+ if (ret < 0)
+ goto epwrinit;
+
+ ret = imx074_video_probe(client);
+ if (ret < 0)
+ goto eprobe;
+
+ return v4l2_async_register_subdev(&priv->subdev);
+
+epwrinit:
+eprobe:
+ v4l2_clk_put(priv->clk);
+ return ret;
}
static int imx074_remove(struct i2c_client *client)
{
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct imx074 *priv = to_imx074(client);
+
+ v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_clk_put(priv->clk);
if (ssdd->free_bus)
ssdd->free_bus(ssdd);
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index dd9089805757..df97033fa6ef 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -16,8 +16,8 @@
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
/*
@@ -94,10 +94,10 @@ struct mt9m001 {
struct v4l2_ctrl *exposure;
};
struct v4l2_rect rect; /* Sensor window */
+ struct v4l2_clk *clk;
const struct mt9m001_datafmt *fmt;
const struct mt9m001_datafmt *fmts;
int num_fmts;
- int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
unsigned int total_h;
unsigned short y_skip_top; /* Lines to skip at the top */
};
@@ -320,36 +320,15 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9m001->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9m001_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
reg->size = 2;
reg->val = reg_read(client, reg->reg);
@@ -364,12 +343,9 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -381,8 +357,9 @@ static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
}
static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -505,11 +482,9 @@ static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd,
switch (data) {
case 0x8411:
case 0x8421:
- mt9m001->model = V4L2_IDENT_MT9M001C12ST;
mt9m001->fmts = mt9m001_colour_fmts;
break;
case 0x8431:
- mt9m001->model = V4L2_IDENT_MT9M001C12STM;
mt9m001->fmts = mt9m001_monochrome_fmts;
break;
default:
@@ -580,7 +555,6 @@ static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
};
static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
- .g_chip_ident = mt9m001_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9m001_g_register,
.s_register = mt9m001_s_register,
@@ -710,9 +684,18 @@ static int mt9m001_probe(struct i2c_client *client,
mt9m001->rect.width = MT9M001_MAX_WIDTH;
mt9m001->rect.height = MT9M001_MAX_HEIGHT;
+ mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(mt9m001->clk)) {
+ ret = PTR_ERR(mt9m001->clk);
+ goto eclkget;
+ }
+
ret = mt9m001_video_probe(ssdd, client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(mt9m001->clk);
+eclkget:
v4l2_ctrl_handler_free(&mt9m001->hdl);
+ }
return ret;
}
@@ -722,6 +705,7 @@ static int mt9m001_remove(struct i2c_client *client)
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ v4l2_clk_put(mt9m001->clk);
v4l2_device_unregister_subdev(&mt9m001->subdev);
v4l2_ctrl_handler_free(&mt9m001->hdl);
mt9m001_video_remove(ssdd);
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index 8bd4e0d2ea03..de3605df47c5 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -17,9 +17,9 @@
#include <linux/module.h>
#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
/*
* MT9M111, MT9M112 and MT9M131:
@@ -205,10 +205,9 @@ struct mt9m111 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *gain;
- int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
- * from v4l2-chip-ident.h */
struct mt9m111_context *ctx;
struct v4l2_rect rect; /* cropping rectangle */
+ struct v4l2_clk *clk;
int width; /* output */
int height; /* sizes */
struct mutex power_lock; /* lock to protect power_count */
@@ -600,24 +599,6 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
return ret;
}
-static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9m111->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9m111_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -625,10 +606,8 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
int val;
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
val = mt9m111_reg_read(client, reg->reg);
reg->size = 2;
@@ -645,12 +624,9 @@ static int mt9m111_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -801,14 +777,14 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- ret = soc_camera_power_on(&client->dev, ssdd);
+ ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk);
if (ret < 0)
return ret;
ret = mt9m111_resume(mt9m111);
if (ret < 0) {
dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
- soc_camera_power_off(&client->dev, ssdd);
+ soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
}
return ret;
@@ -820,7 +796,7 @@ static void mt9m111_power_off(struct mt9m111 *mt9m111)
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
mt9m111_suspend(mt9m111);
- soc_camera_power_off(&client->dev, ssdd);
+ soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
}
static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
@@ -856,7 +832,6 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
};
static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
- .g_chip_ident = mt9m111_g_chip_ident,
.s_power = mt9m111_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9m111_g_register,
@@ -923,12 +898,10 @@ static int mt9m111_video_probe(struct i2c_client *client)
switch (data) {
case 0x143a: /* MT9M111 or MT9M131 */
- mt9m111->model = V4L2_IDENT_MT9M111;
dev_info(&client->dev,
"Detected a MT9M111/MT9M131 chip ID %x\n", data);
break;
case 0x148c: /* MT9M112 */
- mt9m111->model = V4L2_IDENT_MT9M112;
dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
break;
default:
@@ -1002,9 +975,18 @@ static int mt9m111_probe(struct i2c_client *client,
mt9m111->lastpage = -1;
mutex_init(&mt9m111->power_lock);
+ mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(mt9m111->clk)) {
+ ret = PTR_ERR(mt9m111->clk);
+ goto eclkget;
+ }
+
ret = mt9m111_video_probe(client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(mt9m111->clk);
+eclkget:
v4l2_ctrl_handler_free(&mt9m111->hdl);
+ }
return ret;
}
@@ -1013,6 +995,7 @@ static int mt9m111_remove(struct i2c_client *client)
{
struct mt9m111 *mt9m111 = to_mt9m111(client);
+ v4l2_clk_put(mt9m111->clk);
v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index 26a15b87a9a2..47d18d0bafe7 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
@@ -76,7 +76,7 @@ struct mt9t031 {
struct v4l2_ctrl *exposure;
};
struct v4l2_rect rect; /* Sensor window */
- int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+ struct v4l2_clk *clk;
u16 xskip;
u16 yskip;
unsigned int total_h;
@@ -391,36 +391,16 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9t031->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9t031_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
+ reg->size = 1;
reg->val = reg_read(client, reg->reg);
if (reg->val > 0xffff)
@@ -434,12 +414,9 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -595,7 +572,7 @@ static int mt9t031_runtime_resume(struct device *dev)
return 0;
}
-static struct dev_pm_ops mt9t031_dev_pm_ops = {
+static const struct dev_pm_ops mt9t031_dev_pm_ops = {
.runtime_suspend = mt9t031_runtime_suspend,
.runtime_resume = mt9t031_runtime_resume,
};
@@ -610,16 +587,17 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
int ret;
if (on) {
- ret = soc_camera_power_on(&client->dev, ssdd);
+ ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
if (ret < 0)
return ret;
vdev->dev.type = &mt9t031_dev_type;
} else {
vdev->dev.type = NULL;
- soc_camera_power_off(&client->dev, ssdd);
+ soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
}
return 0;
@@ -650,7 +628,6 @@ static int mt9t031_video_probe(struct i2c_client *client)
switch (data) {
case 0x1621:
- mt9t031->model = V4L2_IDENT_MT9T031;
break;
default:
dev_err(&client->dev,
@@ -685,7 +662,6 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
};
static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
- .g_chip_ident = mt9t031_g_chip_ident,
.s_power = mt9t031_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9t031_g_register,
@@ -812,9 +788,18 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->xskip = 1;
mt9t031->yskip = 1;
+ mt9t031->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(mt9t031->clk)) {
+ ret = PTR_ERR(mt9t031->clk);
+ goto eclkget;
+ }
+
ret = mt9t031_video_probe(client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(mt9t031->clk);
+eclkget:
v4l2_ctrl_handler_free(&mt9t031->hdl);
+ }
return ret;
}
@@ -823,6 +808,7 @@ static int mt9t031_remove(struct i2c_client *client)
{
struct mt9t031 *mt9t031 = to_mt9t031(client);
+ v4l2_clk_put(mt9t031->clk);
v4l2_device_unregister_subdev(&mt9t031->subdev);
v4l2_ctrl_handler_free(&mt9t031->hdl);
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index a7256b732804..46f431a13782 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -27,7 +27,7 @@
#include <media/mt9t112.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
/* you can check PLL/clock info */
@@ -90,8 +90,8 @@ struct mt9t112_priv {
struct mt9t112_camera_info *info;
struct i2c_client *client;
struct v4l2_rect frame;
+ struct v4l2_clk *clk;
const struct mt9t112_format *format;
- int model;
int num_formats;
u32 flags;
/* for flags */
@@ -738,17 +738,6 @@ static int mt9t112_init_camera(const struct i2c_client *client)
/************************************************************************
v4l2_subdev_core_ops
************************************************************************/
-static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9t112_g_register(struct v4l2_subdev *sd,
@@ -781,12 +770,12 @@ static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct mt9t112_priv *priv = to_mt9t112(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
- .g_chip_ident = mt9t112_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9t112_g_register,
.s_register = mt9t112_s_register,
@@ -1061,12 +1050,10 @@ static int mt9t112_camera_probe(struct i2c_client *client)
switch (chipid) {
case 0x2680:
devname = "mt9t111";
- priv->model = V4L2_IDENT_MT9T111;
priv->num_formats = 1;
break;
case 0x2682:
devname = "mt9t112";
- priv->model = V4L2_IDENT_MT9T112;
priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
break;
default:
@@ -1108,18 +1095,26 @@ static int mt9t112_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
ret = mt9t112_camera_probe(client);
- if (ret)
- return ret;
/* Cannot fail: using the default supported pixel code */
- mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+ if (!ret)
+ mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+ else
+ v4l2_clk_put(priv->clk);
return ret;
}
static int mt9t112_remove(struct i2c_client *client)
{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ v4l2_clk_put(priv->clk);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index a295e598486f..f9f95f815b1a 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -19,7 +19,7 @@
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
/*
@@ -133,6 +133,11 @@ static const struct mt9v02x_register mt9v024_register = {
.pixclk_fv_lv = MT9V024_PIXCLK_FV_LV,
};
+enum mt9v022_model {
+ MT9V022IX7ATM,
+ MT9V022IX7ATC,
+};
+
struct mt9v022 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
@@ -149,11 +154,12 @@ struct mt9v022 {
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
struct v4l2_rect rect; /* Sensor window */
+ struct v4l2_clk *clk;
const struct mt9v022_datafmt *fmt;
const struct mt9v022_datafmt *fmts;
const struct mt9v02x_register *reg;
int num_fmts;
- int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+ enum mt9v022_model model;
u16 chip_control;
u16 chip_version;
unsigned short y_skip_top; /* Lines to skip at the top */
@@ -406,12 +412,12 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
switch (mf->code) {
case V4L2_MBUS_FMT_Y8_1X8:
case V4L2_MBUS_FMT_Y10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ if (mt9v022->model != MT9V022IX7ATM)
return -EINVAL;
break;
case V4L2_MBUS_FMT_SBGGR8_1X8:
case V4L2_MBUS_FMT_SBGGR10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+ if (mt9v022->model != MT9V022IX7ATC)
return -EINVAL;
break;
default:
@@ -457,36 +463,15 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9v022->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9v022_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
reg->size = 2;
reg->val = reg_read(client, reg->reg);
@@ -501,12 +486,9 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ if (reg->reg > 0xff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -518,8 +500,9 @@ static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
}
static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -706,11 +689,11 @@ static int mt9v022_video_probe(struct i2c_client *client)
if (sensor_type && (!strcmp("colour", sensor_type) ||
!strcmp("color", sensor_type))) {
ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ mt9v022->model = MT9V022IX7ATC;
mt9v022->fmts = mt9v022_colour_fmts;
} else {
ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ mt9v022->model = MT9V022IX7ATM;
mt9v022->fmts = mt9v022_monochrome_fmts;
}
@@ -740,7 +723,7 @@ static int mt9v022_video_probe(struct i2c_client *client)
mt9v022->fmt = &mt9v022->fmts[0];
dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
- data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+ data, mt9v022->model == MT9V022IX7ATM ?
"monochrome" : "colour");
ret = mt9v022_init(client);
@@ -768,7 +751,6 @@ static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
};
static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
- .g_chip_ident = mt9v022_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v022_g_register,
.s_register = mt9v022_s_register,
@@ -957,9 +939,18 @@ static int mt9v022_probe(struct i2c_client *client,
mt9v022->rect.width = MT9V022_MAX_WIDTH;
mt9v022->rect.height = MT9V022_MAX_HEIGHT;
+ mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(mt9v022->clk)) {
+ ret = PTR_ERR(mt9v022->clk);
+ goto eclkget;
+ }
+
ret = mt9v022_video_probe(client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(mt9v022->clk);
+eclkget:
v4l2_ctrl_handler_free(&mt9v022->hdl);
+ }
return ret;
}
@@ -969,6 +960,7 @@ static int mt9v022_remove(struct i2c_client *client)
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ v4l2_clk_put(mt9v022->clk);
v4l2_device_unregister_subdev(&mt9v022->subdev);
if (ssdd->free_bus)
ssdd->free_bus(ssdd);
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index e3168424f9ba..6c6b1c3b45e3 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -22,7 +22,7 @@
#include <linux/videodev2.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
@@ -303,8 +303,8 @@ struct ov2640_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
enum v4l2_mbus_pixelcode cfmt_code;
+ struct v4l2_clk *clk;
const struct ov2640_win_size *win;
- int model;
};
/*
@@ -723,18 +723,6 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov2640_priv *priv = to_ov2640(client);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov2640_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -772,8 +760,9 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov2640_priv *priv = to_ov2640(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
/* Select the nearest higher resolution for capture */
@@ -1009,7 +998,6 @@ static int ov2640_video_probe(struct i2c_client *client)
switch (VERSION(pid, ver)) {
case PID_OV2640:
devname = "ov2640";
- priv->model = V4L2_IDENT_OV2640;
break;
default:
dev_err(&client->dev,
@@ -1034,7 +1022,6 @@ static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
};
static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
- .g_chip_ident = ov2640_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov2640_g_register,
.s_register = ov2640_s_register,
@@ -1113,11 +1100,20 @@ static int ov2640_probe(struct i2c_client *client,
if (priv->hdl.error)
return priv->hdl.error;
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
+
ret = ov2640_video_probe(client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(priv->clk);
+eclkget:
v4l2_ctrl_handler_free(&priv->hdl);
- else
+ } else {
dev_info(&adapter->dev, "OV2640 Probed\n");
+ }
return ret;
}
@@ -1126,6 +1122,7 @@ static int ov2640_remove(struct i2c_client *client)
{
struct ov2640_priv *priv = to_ov2640(client);
+ v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
index 9aa56de69eed..0a5c5d4fedd6 100644
--- a/drivers/media/i2c/soc_camera/ov5642.c
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -24,7 +24,7 @@
#include <linux/v4l2-mediabus.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
/* OV5642 registers */
@@ -610,6 +610,7 @@ struct ov5642 {
struct v4l2_subdev subdev;
const struct ov5642_datafmt *fmt;
struct v4l2_rect crop_rect;
+ struct v4l2_clk *clk;
/* blanking information */
int total_width;
@@ -848,23 +849,6 @@ static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
-static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_OV5642;
- id->revision = 0;
-
- return 0;
-}
-
static int ov5642_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -935,12 +919,13 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov5642 *priv = to_ov5642(client);
int ret;
if (!on)
- return soc_camera_power_off(&client->dev, ssdd);
+ return soc_camera_power_off(&client->dev, ssdd, priv->clk);
- ret = soc_camera_power_on(&client->dev, ssdd);
+ ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
if (ret < 0)
return ret;
@@ -966,7 +951,6 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
.s_power = ov5642_s_power,
- .g_chip_ident = ov5642_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov5642_get_register,
.s_register = ov5642_set_register,
@@ -1021,6 +1005,7 @@ static int ov5642_probe(struct i2c_client *client,
{
struct ov5642 *priv;
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ int ret;
if (!ssdd) {
dev_err(&client->dev, "OV5642: missing platform data!\n");
@@ -1042,13 +1027,23 @@ static int ov5642_probe(struct i2c_client *client,
priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
priv->total_height = BLANKING_MIN_HEIGHT;
- return ov5642_video_probe(client);
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ ret = ov5642_video_probe(client);
+ if (ret < 0)
+ v4l2_clk_put(priv->clk);
+
+ return ret;
}
static int ov5642_remove(struct i2c_client *client)
{
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov5642 *priv = to_ov5642(client);
+ v4l2_clk_put(priv->clk);
if (ssdd->free_bus)
ssdd->free_bus(ssdd);
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
index 991202d4bbae..ab01598ec83f 100644
--- a/drivers/media/i2c/soc_camera/ov6650.c
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -32,7 +32,7 @@
#include <linux/module.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
/* Register definitions */
@@ -196,6 +196,7 @@ struct ov6650 {
struct v4l2_ctrl *blue;
struct v4l2_ctrl *red;
};
+ struct v4l2_clk *clk;
bool half_scale; /* scale down output by 2 */
struct v4l2_rect rect; /* sensor cropping window */
unsigned long pclk_limit; /* from host */
@@ -390,16 +391,6 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-/* Get chip identification */
-static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- id->ident = V4L2_IDENT_OV6650;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov6650_get_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -436,8 +427,9 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov6650 *priv = to_ov6650(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
@@ -879,7 +871,6 @@ static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
};
static struct v4l2_subdev_core_ops ov6650_core_ops = {
- .g_chip_ident = ov6650_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov6650_get_register,
.s_register = ov6650_set_register,
@@ -1025,9 +1016,18 @@ static int ov6650_probe(struct i2c_client *client,
priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
priv->colorspace = V4L2_COLORSPACE_JPEG;
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
+
ret = ov6650_video_probe(client);
- if (ret)
+ if (ret) {
+ v4l2_clk_put(priv->clk);
+eclkget:
v4l2_ctrl_handler_free(&priv->hdl);
+ }
return ret;
}
@@ -1036,6 +1036,7 @@ static int ov6650_remove(struct i2c_client *client)
{
struct ov6650 *priv = to_ov6650(client);
+ v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index 713d62e349f6..7f2b3c8926af 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -26,8 +26,8 @@
#include <media/ov772x.h>
#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
/*
@@ -396,10 +396,10 @@ struct ov772x_win_size {
struct ov772x_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
+ struct v4l2_clk *clk;
struct ov772x_camera_info *info;
const struct ov772x_color_format *cfmt;
const struct ov772x_win_size *win;
- int model;
unsigned short flag_vflip:1;
unsigned short flag_hflip:1;
/* band_filter = COM8[5] ? 256 - BDBASE : 0 */
@@ -620,17 +620,6 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov772x_priv *priv = to_ov772x(sd);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov772x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -668,8 +657,9 @@ static int ov772x_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov772x_priv *priv = to_ov772x(sd);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
@@ -965,11 +955,9 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
switch (VERSION(pid, ver)) {
case OV7720:
devname = "ov7720";
- priv->model = V4L2_IDENT_OV7720;
break;
case OV7725:
devname = "ov7725";
- priv->model = V4L2_IDENT_OV7725;
break;
default:
dev_err(&client->dev,
@@ -997,7 +985,6 @@ static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
};
static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
- .g_chip_ident = ov772x_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov772x_g_register,
.s_register = ov772x_s_register,
@@ -1088,13 +1075,22 @@ static int ov772x_probe(struct i2c_client *client,
if (priv->hdl.error)
return priv->hdl.error;
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
+
ret = ov772x_video_probe(priv);
if (ret < 0) {
+ v4l2_clk_put(priv->clk);
+eclkget:
v4l2_ctrl_handler_free(&priv->hdl);
} else {
priv->cfmt = &ov772x_cfmts[0];
priv->win = &ov772x_win_sizes[0];
}
+
return ret;
}
@@ -1102,6 +1098,7 @@ static int ov772x_remove(struct i2c_client *client)
{
struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
+ v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
index 20ca62d371c1..e968c3fdbd9e 100644
--- a/drivers/media/i2c/soc_camera/ov9640.c
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -28,7 +28,7 @@
#include <linux/videodev2.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
@@ -61,7 +61,7 @@ static const struct ov9640_reg ov9640_regs_dflt[] = {
/* Configurations
* NOTE: for YUV, alter the following registers:
- * COM12 |= OV9640_COM12_YUV_AVG
+ * COM12 |= OV9640_COM12_YUV_AVG
*
* for RGB, alter the following registers:
* COM7 |= OV9640_COM7_RGB
@@ -287,18 +287,6 @@ static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-/* Get chip identification */
-static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
- id->ident = priv->model;
- id->revision = priv->revision;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov9640_get_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -337,8 +325,9 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
/* select nearest higher resolution for capture */
@@ -615,12 +604,10 @@ static int ov9640_video_probe(struct i2c_client *client)
switch (VERSION(pid, ver)) {
case OV9640_V2:
devname = "ov9640";
- priv->model = V4L2_IDENT_OV9640;
priv->revision = 2;
break;
case OV9640_V3:
devname = "ov9640";
- priv->model = V4L2_IDENT_OV9640;
priv->revision = 3;
break;
default:
@@ -644,7 +631,6 @@ static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
};
static struct v4l2_subdev_core_ops ov9640_core_ops = {
- .g_chip_ident = ov9640_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov9640_get_register,
.s_register = ov9640_set_register,
@@ -716,10 +702,18 @@ static int ov9640_probe(struct i2c_client *client,
if (priv->hdl.error)
return priv->hdl.error;
- ret = ov9640_video_probe(client);
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
- if (ret)
+ ret = ov9640_video_probe(client);
+ if (ret) {
+ v4l2_clk_put(priv->clk);
+eclkget:
v4l2_ctrl_handler_free(&priv->hdl);
+ }
return ret;
}
@@ -729,6 +723,7 @@ static int ov9640_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov9640_priv *priv = to_ov9640_sensor(sd);
+ v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov9640.h b/drivers/media/i2c/soc_camera/ov9640.h
index 6b33a972c83c..65d13ff17536 100644
--- a/drivers/media/i2c/soc_camera/ov9640.h
+++ b/drivers/media/i2c/soc_camera/ov9640.h
@@ -199,6 +199,7 @@ struct ov9640_reg {
struct ov9640_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
+ struct v4l2_clk *clk;
int model;
int revision;
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index 012bd6271124..ea76863dfdb4 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -17,7 +17,7 @@
#include <linux/v4l2-mediabus.h>
#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev)
@@ -196,8 +196,8 @@ struct ov9740_reg {
struct ov9740_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
+ struct v4l2_clk *clk;
- int ident;
u16 model;
u8 revision;
u8 manid;
@@ -772,18 +772,6 @@ static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-/* Get chip identification */
-static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov9740_priv *priv = to_ov9740(sd);
-
- id->ident = priv->ident;
- id->revision = priv->revision;
-
- return 0;
-}
-
static int ov9740_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -792,7 +780,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
int ret;
if (on) {
- ret = soc_camera_power_on(&client->dev, ssdd);
+ ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
if (ret < 0)
return ret;
@@ -806,7 +794,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
priv->current_enable = true;
}
- soc_camera_power_off(&client->dev, ssdd);
+ soc_camera_power_off(&client->dev, ssdd, priv->clk);
}
return 0;
@@ -887,8 +875,6 @@ static int ov9740_video_probe(struct i2c_client *client)
goto done;
}
- priv->ident = V4L2_IDENT_OV9740;
-
dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
"Manufacturer 0x%02x, SMIA Version 0x%02x\n",
priv->model, priv->revision, priv->manid, priv->smiaver);
@@ -927,7 +913,6 @@ static struct v4l2_subdev_video_ops ov9740_video_ops = {
};
static struct v4l2_subdev_core_ops ov9740_core_ops = {
- .g_chip_ident = ov9740_g_chip_ident,
.s_power = ov9740_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov9740_get_register,
@@ -975,9 +960,18 @@ static int ov9740_probe(struct i2c_client *client,
if (priv->hdl.error)
return priv->hdl.error;
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
+
ret = ov9740_video_probe(client);
- if (ret < 0)
+ if (ret < 0) {
+ v4l2_clk_put(priv->clk);
+eclkget:
v4l2_ctrl_handler_free(&priv->hdl);
+ }
return ret;
}
@@ -986,6 +980,7 @@ static int ov9740_remove(struct i2c_client *client)
{
struct ov9740_priv *priv = i2c_get_clientdata(client);
+ v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
index 1f9ec3b06b4e..7e6d97847874 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -17,8 +17,8 @@
#include <media/rj54n1cb0c.h>
#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#define RJ54N1_DEV_CODE 0x0400
@@ -151,6 +151,7 @@ struct rj54n1_clock_div {
struct rj54n1 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
+ struct v4l2_clk *clk;
struct rj54n1_clock_div clk_div;
const struct rj54n1_datafmt *fmt;
struct v4l2_rect rect; /* Sensor window */
@@ -1120,37 +1121,16 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_RJ54N1CB0C;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int rj54n1_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
- reg->reg < 0x400 || reg->reg > 0x1fff)
+ if (reg->reg < 0x400 || reg->reg > 0x1fff)
/* Registers > 0x0800 are only available from Sharp support */
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
reg->size = 1;
reg->val = reg_read(client, reg->reg);
@@ -1165,14 +1145,10 @@ static int rj54n1_s_register(struct v4l2_subdev *sd,
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
- reg->reg < 0x400 || reg->reg > 0x1fff)
+ if (reg->reg < 0x400 || reg->reg > 0x1fff)
/* Registers >= 0x0800 are only available from Sharp support */
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -1184,8 +1160,9 @@ static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
}
static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1233,7 +1210,6 @@ static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
};
static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
- .g_chip_ident = rj54n1_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = rj54n1_g_register,
.s_register = rj54n1_s_register,
@@ -1382,9 +1358,18 @@ static int rj54n1_probe(struct i2c_client *client,
rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
(clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
+ rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(rj54n1->clk)) {
+ ret = PTR_ERR(rj54n1->clk);
+ goto eclkget;
+ }
+
ret = rj54n1_video_probe(client, rj54n1_priv);
- if (ret < 0)
+ if (ret < 0) {
+ v4l2_clk_put(rj54n1->clk);
+eclkget:
v4l2_ctrl_handler_free(&rj54n1->hdl);
+ }
return ret;
}
@@ -1394,6 +1379,7 @@ static int rj54n1_remove(struct i2c_client *client)
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ v4l2_clk_put(rj54n1->clk);
v4l2_device_unregister_subdev(&rj54n1->subdev);
if (ssdd->free_bus)
ssdd->free_bus(ssdd);
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index bad90b16a6dd..ab54628d9411 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -27,7 +27,7 @@
#include <media/soc_camera.h>
#include <media/tw9910.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
#define GET_ID(val) ((val & 0xF8) >> 3)
@@ -228,6 +228,7 @@ struct tw9910_scale_ctrl {
struct tw9910_priv {
struct v4l2_subdev subdev;
+ struct v4l2_clk *clk;
struct tw9910_video_info *info;
const struct tw9910_scale_ctrl *scale;
v4l2_std_id norm;
@@ -518,18 +519,6 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
return 0;
}
-static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- id->ident = V4L2_IDENT_TW9910;
- id->revision = priv->revision;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int tw9910_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -540,6 +529,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
if (reg->reg > 0xff)
return -EINVAL;
+ reg->size = 1;
ret = i2c_smbus_read_byte_data(client, reg->reg);
if (ret < 0)
return ret;
@@ -570,8 +560,9 @@ static int tw9910_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ struct tw9910_priv *priv = to_tw9910(client);
- return soc_camera_set_power(&client->dev, ssdd, on);
+ return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
}
static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
@@ -823,7 +814,6 @@ done:
}
static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
- .g_chip_ident = tw9910_g_chip_ident,
.s_std = tw9910_s_std,
.g_std = tw9910_g_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -912,6 +902,7 @@ static int tw9910_probe(struct i2c_client *client,
struct i2c_adapter *adapter =
to_i2c_adapter(client->dev.parent);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ int ret;
if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "TW9910: missing platform data!\n");
@@ -935,11 +926,21 @@ static int tw9910_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
- return tw9910_video_probe(client);
+ priv->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ ret = tw9910_video_probe(client);
+ if (ret < 0)
+ v4l2_clk_put(priv->clk);
+
+ return ret;
}
static int tw9910_remove(struct i2c_client *client)
{
+ struct tw9910_priv *priv = to_tw9910(client);
+ v4l2_clk_put(priv->clk);
return 0;
}
diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c
index 38cbea98764c..32d82320b485 100644
--- a/drivers/media/i2c/sony-btf-mpx.c
+++ b/drivers/media/i2c/sony-btf-mpx.c
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL v2");
static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n");
+MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on");
/* #define MPX_DEBUG */
@@ -355,7 +355,7 @@ static int sony_btf_mpx_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- t = kzalloc(sizeof(struct sony_btf_mpx), GFP_KERNEL);
+ t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
@@ -374,7 +374,6 @@ static int sony_btf_mpx_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index e9d95bda2ab1..ae9432637fcb 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -23,6 +23,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
+#include <media/v4l2-ctrls.h>
#include <media/sr030pc30.h>
static int debug;
@@ -142,17 +143,24 @@ module_param(debug, int, 0644);
struct sr030pc30_info {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
const struct sr030pc30_platform_data *pdata;
const struct sr030pc30_format *curr_fmt;
const struct sr030pc30_frmsize *curr_win;
- unsigned int auto_wb:1;
- unsigned int auto_exp:1;
unsigned int hflip:1;
unsigned int vflip:1;
unsigned int sleep:1;
- unsigned int exposure;
- u8 blue_balance;
- u8 red_balance;
+ struct {
+ /* auto whitebalance control cluster */
+ struct v4l2_ctrl *awb;
+ struct v4l2_ctrl *red;
+ struct v4l2_ctrl *blue;
+ };
+ struct {
+ /* auto exposure control cluster */
+ struct v4l2_ctrl *autoexp;
+ struct v4l2_ctrl *exp;
+ };
u8 i2c_reg_page;
};
@@ -173,52 +181,6 @@ struct i2c_regval {
u16 val;
};
-static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto White Balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- }, {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- }, {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Auto Exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- }, {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = EXPOS_MIN_MS,
- .maximum = EXPOS_MAX_MS,
- .step = 1,
- .default_value = 1,
- }, {
- }
-};
-
/* supported resolutions */
static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
{
@@ -394,48 +356,6 @@ static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
return ret;
}
-static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
- /* auto anti-flicker is also enabled here */
- int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
- if (!ret)
- info->auto_exp = on;
- return ret;
-}
-
-static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
-
- int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
- if (!ret)
- ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
- if (!ret) { /* Turn off AE */
- info->exposure = value;
- ret = sr030pc30_enable_autoexposure(sd, 0);
- }
- return ret;
-}
-
-/* Automatic white balance control */
-static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
- if (!ret)
- ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
- if (!ret)
- info->auto_wb = on;
-
- return ret;
-}
-
static int sr030pc30_set_flip(struct v4l2_subdev *sd)
{
struct sr030pc30_info *info = to_sr030pc30(sd);
@@ -498,107 +418,56 @@ static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
return -EINVAL;
}
-static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
- if (qc->id == sr030pc30_ctrl[i].id) {
- *qc = sr030pc30_ctrl[i];
- v4l2_dbg(1, debug, sd, "%s id: %d\n",
- __func__, qc->id);
- return 0;
- }
-
- return -EINVAL;
-}
-
-static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
+static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
{
- int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
- if (!ret)
- to_sr030pc30(sd)->blue_balance = value;
- return ret;
-}
-
-static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
-{
- int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
- if (!ret)
- to_sr030pc30(sd)->red_balance = value;
- return ret;
-}
-
-static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
- struct v4l2_control *ctrl)
-{
- int i, ret = 0;
-
- for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
- if (ctrl->id == sr030pc30_ctrl[i].id)
- break;
-
- if (i == ARRAY_SIZE(sr030pc30_ctrl))
- return -EINVAL;
-
- if (ctrl->value < sr030pc30_ctrl[i].minimum ||
- ctrl->value > sr030pc30_ctrl[i].maximum)
- return -ERANGE;
+ struct sr030pc30_info *info =
+ container_of(ctrl->handler, struct sr030pc30_info, hdl);
+ struct v4l2_subdev *sd = &info->sd;
+ int ret = 0;
v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
- __func__, ctrl->id, ctrl->value);
+ __func__, ctrl->id, ctrl->val);
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
- sr030pc30_enable_autowhitebalance(sd, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- ret = sr030pc30_set_bluebalance(sd, ctrl->value);
- break;
- case V4L2_CID_RED_BALANCE:
- ret = sr030pc30_set_redbalance(sd, ctrl->value);
- break;
- case V4L2_CID_EXPOSURE_AUTO:
- sr030pc30_enable_autoexposure(sd,
- ctrl->value == V4L2_EXPOSURE_AUTO);
- break;
- case V4L2_CID_EXPOSURE:
- ret = sr030pc30_set_exposure(sd, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
-
- return ret;
-}
-
-static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
- struct v4l2_control *ctrl)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+ if (ctrl->is_new) {
+ ret = cam_i2c_write(sd, AWB_CTL2_REG,
+ ctrl->val ? 0x2E : 0x2F);
+ if (!ret)
+ ret = cam_i2c_write(sd, AWB_CTL1_REG,
+ ctrl->val ? 0xFB : 0x7B);
+ }
+ if (!ret && info->blue->is_new)
+ ret = cam_i2c_write(sd, MWB_BGAIN_REG, info->blue->val);
+ if (!ret && info->red->is_new)
+ ret = cam_i2c_write(sd, MWB_RGAIN_REG, info->red->val);
+ return ret;
- switch (ctrl->id) {
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ctrl->value = info->auto_wb;
- break;
- case V4L2_CID_BLUE_BALANCE:
- ctrl->value = info->blue_balance;
- break;
- case V4L2_CID_RED_BALANCE:
- ctrl->value = info->red_balance;
- break;
case V4L2_CID_EXPOSURE_AUTO:
- ctrl->value = info->auto_exp;
- break;
- case V4L2_CID_EXPOSURE:
- ctrl->value = info->exposure;
- break;
+ /* auto anti-flicker is also enabled here */
+ if (ctrl->is_new)
+ ret = cam_i2c_write(sd, AE_CTL1_REG,
+ ctrl->val == V4L2_EXPOSURE_AUTO ? 0xDC : 0x0C);
+ if (info->exp->is_new) {
+ unsigned long expos = info->exp->val;
+
+ expos = expos * info->pdata->clk_rate / (8 * 1000);
+
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_TIMEH_REG,
+ expos >> 16 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_TIMEM_REG,
+ expos >> 8 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_TIMEL_REG,
+ expos & 0xFF);
+ }
+ return ret;
default:
return -EINVAL;
}
+
return 0;
}
@@ -752,11 +621,19 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
+static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
+ .s_ctrl = sr030pc30_s_ctrl,
+};
+
static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
.s_power = sr030pc30_s_power,
- .queryctrl = sr030pc30_queryctrl,
- .s_ctrl = sr030pc30_s_ctrl,
- .g_ctrl = sr030pc30_g_ctrl,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
@@ -807,6 +684,7 @@ static int sr030pc30_probe(struct i2c_client *client,
{
struct sr030pc30_info *info;
struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
const struct sr030pc30_platform_data *pdata
= client->dev.platform_data;
int ret;
@@ -820,7 +698,7 @@ static int sr030pc30_probe(struct i2c_client *client,
if (ret)
return ret;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -830,10 +708,31 @@ static int sr030pc30_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
+ hdl = &info->hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
+ info->awb = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ info->red = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
+ info->blue = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
+ info->autoexp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 1);
+ info->exp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+ V4L2_CID_EXPOSURE, EXPOS_MIN_MS, EXPOS_MAX_MS, 1, 30);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ return err;
+ }
+ v4l2_ctrl_auto_cluster(3, &info->awb, 0, false);
+ v4l2_ctrl_auto_cluster(2, &info->autoexp, V4L2_EXPOSURE_MANUAL, false);
+ v4l2_ctrl_handler_setup(hdl);
+
info->i2c_reg_page = -1;
info->hflip = 1;
- info->auto_exp = 1;
- info->exposure = 30;
return 0;
}
@@ -841,10 +740,9 @@ static int sr030pc30_probe(struct i2c_client *client,
static int sr030pc30_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct sr030pc30_info *info = to_sr030pc30(sd);
v4l2_device_unregister_subdev(sd);
- kfree(info);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
return 0;
}
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index 28b5121881f5..72af644fa051 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -359,7 +359,7 @@ static int tda7432_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
- t = kzalloc(sizeof(*t), GFP_KERNEL);
+ t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
if (!t)
return -ENOMEM;
sd = &t->sd;
@@ -380,7 +380,6 @@ static int tda7432_probe(struct i2c_client *client,
int err = t->hdl.error;
v4l2_ctrl_handler_free(&t->hdl);
- kfree(t);
return err;
}
v4l2_ctrl_cluster(2, &t->bass);
@@ -406,7 +405,6 @@ static int tda7432_remove(struct i2c_client *client)
tda7432_set(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&t->hdl);
- kfree(t);
return 0;
}
diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c
index 01441e35d88b..fbdff8b24eec 100644
--- a/drivers/media/i2c/tda9840.c
+++ b/drivers/media/i2c/tda9840.c
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
MODULE_DESCRIPTION("tda9840 driver");
@@ -145,26 +144,14 @@ static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
return 0;
}
-static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
-}
-
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops tda9840_core_ops = {
- .g_chip_ident = tda9840_g_chip_ident,
-};
-
static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
.s_tuner = tda9840_s_tuner,
.g_tuner = tda9840_g_tuner,
};
static const struct v4l2_subdev_ops tda9840_ops = {
- .core = &tda9840_core_ops,
.tuner = &tda9840_tuner_ops,
};
@@ -184,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
@@ -201,7 +188,6 @@ static int tda9840_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
return 0;
}
diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c
index 3d5b06a5c308..bbe1a99fda36 100644
--- a/drivers/media/i2c/tea6415c.c
+++ b/drivers/media/i2c/tea6415c.c
@@ -33,7 +33,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include "tea6415c.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -119,25 +118,13 @@ static int tea6415c_s_routing(struct v4l2_subdev *sd,
return ret;
}
-static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
-}
-
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
- .g_chip_ident = tea6415c_g_chip_ident,
-};
-
static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
.s_routing = tea6415c_s_routing,
};
static const struct v4l2_subdev_ops tea6415c_ops = {
- .core = &tea6415c_core_ops,
.video = &tea6415c_video_ops,
};
@@ -152,7 +139,7 @@ static int tea6415c_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
@@ -164,7 +151,6 @@ static int tea6415c_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
return 0;
}
diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c
index 38757217a074..30a8d75771af 100644
--- a/drivers/media/i2c/tea6420.c
+++ b/drivers/media/i2c/tea6420.c
@@ -33,7 +33,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include "tea6420.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -90,25 +89,13 @@ static int tea6420_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
-}
-
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops tea6420_core_ops = {
- .g_chip_ident = tea6420_g_chip_ident,
-};
-
static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
.s_routing = tea6420_s_routing,
};
static const struct v4l2_subdev_ops tea6420_ops = {
- .core = &tea6420_core_ops,
.audio = &tea6420_audio_ops,
};
@@ -125,7 +112,7 @@ static int tea6420_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
@@ -146,7 +133,6 @@ static int tea6420_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
return 0;
}
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index c4339556a2ea..0a2dacbd7a63 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <media/ths7303.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-device.h>
#define THS7303_CHANNEL_1 1
@@ -35,11 +34,10 @@
struct ths7303_state {
struct v4l2_subdev sd;
- struct ths7303_platform_data pdata;
+ const struct ths7303_platform_data *pdata;
struct v4l2_bt_timings bt;
int std_id;
int stream_on;
- int driver_data;
};
enum ths7303_filter_mode {
@@ -89,7 +87,7 @@ int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ths7303_state *state = to_state(sd);
- struct ths7303_platform_data *pdata = &state->pdata;
+ const struct ths7303_platform_data *pdata = state->pdata;
u8 val, sel = 0;
int err, disable = 0;
@@ -212,15 +210,6 @@ static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
return ths7303_config(sd);
}
-static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ths7303_state *state = to_state(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->driver_data, 0);
-}
-
static const struct v4l2_subdev_video_ops ths7303_video_ops = {
.s_stream = ths7303_s_stream,
.s_std_output = ths7303_s_std_output,
@@ -232,13 +221,6 @@ static const struct v4l2_subdev_video_ops ths7303_video_ops = {
static int ths7303_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
reg->size = 1;
reg->val = ths7303_read(sd, reg->reg);
return 0;
@@ -247,13 +229,6 @@ static int ths7303_g_register(struct v4l2_subdev *sd,
static int ths7303_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
ths7303_write(sd, reg->reg, reg->val);
return 0;
}
@@ -340,7 +315,6 @@ static int ths7303_log_status(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_core_ops ths7303_core_ops = {
- .g_chip_ident = ths7303_g_chip_ident,
.log_status = ths7303_log_status,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ths7303_g_register,
@@ -353,32 +327,6 @@ static const struct v4l2_subdev_ops ths7303_ops = {
.video = &ths7303_video_ops,
};
-static int ths7303_setup(struct v4l2_subdev *sd)
-{
- struct ths7303_state *state = to_state(sd);
- struct ths7303_platform_data *pdata = &state->pdata;
- int ret;
- u8 mask;
-
- state->stream_on = pdata->init_enable;
-
- mask = state->stream_on ? 0xff : 0xf8;
-
- ret = ths7303_write(sd, THS7303_CHANNEL_1, pdata->ch_1 & mask);
- if (ret)
- return ret;
-
- ret = ths7303_write(sd, THS7303_CHANNEL_2, pdata->ch_2 & mask);
- if (ret)
- return ret;
-
- ret = ths7303_write(sd, THS7303_CHANNEL_3, pdata->ch_3 & mask);
- if (ret)
- return ret;
-
- return 0;
-}
-
static int ths7303_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -386,6 +334,11 @@ static int ths7303_probe(struct i2c_client *client,
struct ths7303_state *state;
struct v4l2_subdev *sd;
+ if (pdata == NULL) {
+ dev_err(&client->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
@@ -397,20 +350,14 @@ static int ths7303_probe(struct i2c_client *client,
if (!state)
return -ENOMEM;
- if (!pdata)
- v4l_warn(client, "No platform data, using default data!\n");
- else
- state->pdata = *pdata;
-
+ state->pdata = pdata;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
- /* store the driver data to differntiate the chip */
- state->driver_data = (int)id->driver_data;
-
- if (ths7303_setup(sd) < 0) {
- v4l_err(client, "init failed\n");
- return -EIO;
+ /* set to default 480I_576I filter mode */
+ if (ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I) < 0) {
+ v4l_err(client, "Setting to 480I_576I filter mode failed!\n");
+ return -EINVAL;
}
return 0;
@@ -426,8 +373,8 @@ static int ths7303_remove(struct i2c_client *client)
}
static const struct i2c_device_id ths7303_id[] = {
- {"ths7303", V4L2_IDENT_THS7303},
- {"ths7353", V4L2_IDENT_THS7353},
+ {"ths7303", 0},
+ {"ths7353", 0},
{},
};
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
new file mode 100644
index 000000000000..a24f90c5261c
--- /dev/null
+++ b/drivers/media/i2c/ths8200.c
@@ -0,0 +1,556 @@
+/*
+ * ths8200 - Texas Instruments THS8200 video encoder driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/v4l2-dv-timings.h>
+
+#include <media/v4l2-device.h>
+
+#include "ths8200_regs.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+MODULE_DESCRIPTION("Texas Instruments THS8200 video encoder driver");
+MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
+MODULE_AUTHOR("Martin Bugge <martin.bugge@cisco.com>");
+MODULE_LICENSE("GPL v2");
+
+struct ths8200_state {
+ struct v4l2_subdev sd;
+ uint8_t chip_version;
+ /* Is the ths8200 powered on? */
+ bool power_on;
+ struct v4l2_dv_timings dv_timings;
+};
+
+static const struct v4l2_dv_timings ths8200_timings[] = {
+ V4L2_DV_BT_CEA_720X480P59_94,
+ V4L2_DV_BT_CEA_1280X720P24,
+ V4L2_DV_BT_CEA_1280X720P25,
+ V4L2_DV_BT_CEA_1280X720P30,
+ V4L2_DV_BT_CEA_1280X720P50,
+ V4L2_DV_BT_CEA_1280X720P60,
+ V4L2_DV_BT_CEA_1920X1080P24,
+ V4L2_DV_BT_CEA_1920X1080P25,
+ V4L2_DV_BT_CEA_1920X1080P30,
+ V4L2_DV_BT_CEA_1920X1080P50,
+ V4L2_DV_BT_CEA_1920X1080P60,
+};
+
+static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ths8200_state, sd);
+}
+
+static inline unsigned hblanking(const struct v4l2_bt_timings *t)
+{
+ return t->hfrontporch + t->hsync + t->hbackporch;
+}
+
+static inline unsigned htotal(const struct v4l2_bt_timings *t)
+{
+ return t->width + t->hfrontporch + t->hsync + t->hbackporch;
+}
+
+static inline unsigned vblanking(const struct v4l2_bt_timings *t)
+{
+ return t->vfrontporch + t->vsync + t->vbackporch;
+}
+
+static inline unsigned vtotal(const struct v4l2_bt_timings *t)
+{
+ return t->height + t->vfrontporch + t->vsync + t->vbackporch;
+}
+
+static int ths8200_read(struct v4l2_subdev *sd, u8 reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ths8200_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret == 0)
+ return 0;
+ }
+ v4l2_err(sd, "I2C Write Problem\n");
+ return ret;
+}
+
+/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
+ * and then the value-mask (to be OR-ed).
+ */
+static inline void
+ths8200_write_and_or(struct v4l2_subdev *sd, u8 reg,
+ uint8_t clr_mask, uint8_t val_mask)
+{
+ ths8200_write(sd, reg, (ths8200_read(sd, reg) & clr_mask) | val_mask);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+static int ths8200_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ reg->val = ths8200_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+
+ return 0;
+}
+
+static int ths8200_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ ths8200_write(sd, reg->reg & 0xff, reg->val & 0xff);
+
+ return 0;
+}
+#endif
+
+static void ths8200_print_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings,
+ const char *txt, bool detailed)
+{
+ struct v4l2_bt_timings *bt = &timings->bt;
+ u32 htot, vtot;
+
+ if (timings->type != V4L2_DV_BT_656_1120)
+ return;
+
+ htot = htotal(bt);
+ vtot = vtotal(bt);
+
+ v4l2_info(sd, "%s %dx%d%s%d (%dx%d)",
+ txt, bt->width, bt->height, bt->interlaced ? "i" : "p",
+ (htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0,
+ htot, vtot);
+
+ if (detailed) {
+ v4l2_info(sd, " horizontal: fp = %d, %ssync = %d, bp = %d\n",
+ bt->hfrontporch,
+ (bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
+ bt->hsync, bt->hbackporch);
+ v4l2_info(sd, " vertical: fp = %d, %ssync = %d, bp = %d\n",
+ bt->vfrontporch,
+ (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
+ bt->vsync, bt->vbackporch);
+ v4l2_info(sd,
+ " pixelclock: %lld, flags: 0x%x, standards: 0x%x\n",
+ bt->pixelclock, bt->flags, bt->standards);
+ }
+}
+
+static int ths8200_log_status(struct v4l2_subdev *sd)
+{
+ struct ths8200_state *state = to_state(sd);
+ uint8_t reg_03 = ths8200_read(sd, THS8200_CHIP_CTL);
+
+ v4l2_info(sd, "----- Chip status -----\n");
+ v4l2_info(sd, "version: %u\n", state->chip_version);
+ v4l2_info(sd, "power: %s\n", (reg_03 & 0x0c) ? "off" : "on");
+ v4l2_info(sd, "reset: %s\n", (reg_03 & 0x01) ? "off" : "on");
+ v4l2_info(sd, "test pattern: %s\n",
+ (reg_03 & 0x20) ? "enabled" : "disabled");
+ v4l2_info(sd, "format: %ux%u\n",
+ ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_MSB) * 256 +
+ ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_LSB),
+ (ths8200_read(sd, THS8200_DTG2_LINE_CNT_MSB) & 0x07) * 256 +
+ ths8200_read(sd, THS8200_DTG2_LINE_CNT_LSB));
+ ths8200_print_timings(sd, &state->dv_timings,
+ "Configured format:", true);
+
+ return 0;
+}
+
+/* Power up/down ths8200 */
+static int ths8200_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct ths8200_state *state = to_state(sd);
+
+ v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
+
+ state->power_on = on;
+
+ /* Power up/down - leave in reset state until input video is present */
+ ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xf2, (on ? 0x00 : 0x0c));
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops ths8200_core_ops = {
+ .log_status = ths8200_log_status,
+ .s_power = ths8200_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ths8200_g_register,
+ .s_register = ths8200_s_register,
+#endif
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int ths8200_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ths8200_state *state = to_state(sd);
+
+ if (enable && !state->power_on)
+ ths8200_s_power(sd, true);
+
+ ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xfe,
+ (enable ? 0x01 : 0x00));
+
+ v4l2_dbg(1, debug, sd, "%s: %sable\n",
+ __func__, (enable ? "en" : "dis"));
+
+ return 0;
+}
+
+static void ths8200_core_init(struct v4l2_subdev *sd)
+{
+ /* setup clocks */
+ ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0x3f, 0xc0);
+
+ /**** Data path control (DATA) ****/
+ /* Set FSADJ 700 mV,
+ * bypass 422-444 interpolation,
+ * input format 30 bit RGB444
+ */
+ ths8200_write(sd, THS8200_DATA_CNTL, 0x70);
+
+ /* DTG Mode (Video blocked during blanking
+ * VESA slave
+ */
+ ths8200_write(sd, THS8200_DTG1_MODE, 0x87);
+
+ /**** Display Timing Generator Control, Part 1 (DTG1). ****/
+
+ /* Disable embedded syncs on the output by setting
+ * the amplitude to zero for all channels.
+ */
+ ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x2a);
+ ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x2a);
+}
+
+static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
+{
+ uint8_t polarity = 0;
+ uint16_t line_start_active_video = (bt->vsync + bt->vbackporch);
+ uint16_t line_start_front_porch = (vtotal(bt) - bt->vfrontporch);
+
+ /*** System ****/
+ /* Set chip in reset while it is configured */
+ ths8200_s_stream(sd, false);
+
+ /* configure video output timings */
+ ths8200_write(sd, THS8200_DTG1_SPEC_A, bt->hsync);
+ ths8200_write(sd, THS8200_DTG1_SPEC_B, bt->hfrontporch);
+
+ /* Zero for progressive scan formats.*/
+ if (!bt->interlaced)
+ ths8200_write(sd, THS8200_DTG1_SPEC_C, 0x00);
+
+ /* Distance from leading edge of h sync to start of active video.
+ * MSB in 0x2b
+ */
+ ths8200_write(sd, THS8200_DTG1_SPEC_D_LSB,
+ (bt->hbackporch + bt->hsync) & 0xff);
+ /* Zero for SDTV-mode. MSB in 0x2b */
+ ths8200_write(sd, THS8200_DTG1_SPEC_E_LSB, 0x00);
+ /*
+ * MSB for dtg1_spec(d/e/h). See comment for
+ * corresponding LSB registers.
+ */
+ ths8200_write(sd, THS8200_DTG1_SPEC_DEH_MSB,
+ ((bt->hbackporch + bt->hsync) & 0x100) >> 1);
+
+ /* h front porch */
+ ths8200_write(sd, THS8200_DTG1_SPEC_K_LSB, (bt->hfrontporch) & 0xff);
+ ths8200_write(sd, THS8200_DTG1_SPEC_K_MSB,
+ ((bt->hfrontporch) & 0x700) >> 8);
+
+ /* Half the line length. Used to calculate SDTV line types. */
+ ths8200_write(sd, THS8200_DTG1_SPEC_G_LSB, (htotal(bt)/2) & 0xff);
+ ths8200_write(sd, THS8200_DTG1_SPEC_G_MSB,
+ ((htotal(bt)/2) >> 8) & 0x0f);
+
+ /* Total pixels per line (ex. 720p: 1650) */
+ ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_MSB, htotal(bt) >> 8);
+ ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_LSB, htotal(bt) & 0xff);
+
+ /* Frame height and field height */
+ /* Field height should be programmed higher than frame_size for
+ * progressive scan formats
+ */
+ ths8200_write(sd, THS8200_DTG1_FRAME_FIELD_SZ_MSB,
+ ((vtotal(bt) >> 4) & 0xf0) + 0x7);
+ ths8200_write(sd, THS8200_DTG1_FRAME_SZ_LSB, vtotal(bt) & 0xff);
+
+ /* Should be programmed higher than frame_size
+ * for progressive formats
+ */
+ if (!bt->interlaced)
+ ths8200_write(sd, THS8200_DTG1_FIELD_SZ_LSB, 0xff);
+
+ /**** Display Timing Generator Control, Part 2 (DTG2). ****/
+ /* Set breakpoint line numbers and types
+ * THS8200 generates line types with different properties. A line type
+ * that sets all the RGB-outputs to zero is used in the blanking areas,
+ * while a line type that enable the RGB-outputs is used in active video
+ * area. The line numbers for start of active video, start of front
+ * porch and after the last line in the frame must be set with the
+ * corresponding line types.
+ *
+ * Line types:
+ * 0x9 - Full normal sync pulse: Blocks data when dtg1_pass is off.
+ * Used in blanking area.
+ * 0x0 - Active video: Video data is always passed. Used in active
+ * video area.
+ */
+ ths8200_write_and_or(sd, THS8200_DTG2_BP1_2_MSB, 0x88,
+ ((line_start_active_video >> 4) & 0x70) +
+ ((line_start_front_porch >> 8) & 0x07));
+ ths8200_write(sd, THS8200_DTG2_BP3_4_MSB, ((vtotal(bt)) >> 4) & 0x70);
+ ths8200_write(sd, THS8200_DTG2_BP1_LSB, line_start_active_video & 0xff);
+ ths8200_write(sd, THS8200_DTG2_BP2_LSB, line_start_front_porch & 0xff);
+ ths8200_write(sd, THS8200_DTG2_BP3_LSB, (vtotal(bt)) & 0xff);
+
+ /* line types */
+ ths8200_write(sd, THS8200_DTG2_LINETYPE1, 0x90);
+ ths8200_write(sd, THS8200_DTG2_LINETYPE2, 0x90);
+
+ /* h sync width transmitted */
+ ths8200_write(sd, THS8200_DTG2_HLENGTH_LSB, bt->hsync & 0xff);
+ ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0x3f,
+ (bt->hsync >> 2) & 0xc0);
+
+ /* The pixel value h sync is asserted on */
+ ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0xe0,
+ (htotal(bt) >> 8) & 0x1f);
+ ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, htotal(bt));
+
+ /* v sync width transmitted */
+ ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync) & 0xff);
+ ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0x3f,
+ ((bt->vsync) >> 2) & 0xc0);
+
+ /* The pixel value v sync is asserted on */
+ ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0xf8,
+ (vtotal(bt)>>8) & 0x7);
+ ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt));
+
+ /* For progressive video vlength2 must be set to all 0 and vdly2 must
+ * be set to all 1.
+ */
+ ths8200_write(sd, THS8200_DTG2_VLENGTH2_LSB, 0x00);
+ ths8200_write(sd, THS8200_DTG2_VLENGTH2_MSB_VDLY2_MSB, 0x07);
+ ths8200_write(sd, THS8200_DTG2_VDLY2_LSB, 0xff);
+
+ /* Internal delay factors to synchronize the sync pulses and the data */
+ /* Experimental values delays (hor 4, ver 1) */
+ ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, (htotal(bt)>>8) & 0x1f);
+ ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, (htotal(bt) - 4) & 0xff);
+ ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_MSB, 0);
+ ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 1);
+
+ /* Polarity of received and transmitted sync signals */
+ if (bt->polarities & V4L2_DV_HSYNC_POS_POL) {
+ polarity |= 0x01; /* HS_IN */
+ polarity |= 0x08; /* HS_OUT */
+ }
+ if (bt->polarities & V4L2_DV_VSYNC_POS_POL) {
+ polarity |= 0x02; /* VS_IN */
+ polarity |= 0x10; /* VS_OUT */
+ }
+
+ /* RGB mode, no embedded timings */
+ /* Timing of video input bus is derived from HS, VS, and FID dedicated
+ * inputs
+ */
+ ths8200_write(sd, THS8200_DTG2_CNTL, 0x47 | polarity);
+
+ /* leave reset */
+ ths8200_s_stream(sd, true);
+
+ v4l2_dbg(1, debug, sd, "%s: frame %dx%d, polarity %d\n"
+ "horizontal: front porch %d, back porch %d, sync %d\n"
+ "vertical: sync %d\n", __func__, htotal(bt), vtotal(bt),
+ polarity, bt->hfrontporch, bt->hbackporch,
+ bt->hsync, bt->vsync);
+}
+
+static int ths8200_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ struct ths8200_state *state = to_state(sd);
+ int i;
+
+ v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+ if (timings->type != V4L2_DV_BT_656_1120)
+ return -EINVAL;
+
+ /* TODO Support interlaced formats */
+ if (timings->bt.interlaced) {
+ v4l2_dbg(1, debug, sd, "TODO Support interlaced formats\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ths8200_timings); i++) {
+ if (v4l_match_dv_timings(&ths8200_timings[i], timings, 10))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ths8200_timings)) {
+ v4l2_dbg(1, debug, sd, "Unsupported format\n");
+ return -EINVAL;
+ }
+
+ timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
+
+ /* save timings */
+ state->dv_timings = *timings;
+
+ ths8200_setup(sd, &timings->bt);
+
+ return 0;
+}
+
+static int ths8200_g_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ struct ths8200_state *state = to_state(sd);
+
+ v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+ *timings = state->dv_timings;
+
+ return 0;
+}
+
+static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
+{
+ /* Check requested format index is within range */
+ if (timings->index >= ARRAY_SIZE(ths8200_timings))
+ return -EINVAL;
+
+ timings->timings = ths8200_timings[timings->index];
+
+ return 0;
+}
+
+static int ths8200_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ cap->type = V4L2_DV_BT_656_1120;
+ cap->bt.max_width = 1920;
+ cap->bt.max_height = 1080;
+ cap->bt.min_pixelclock = 27000000;
+ cap->bt.max_pixelclock = 148500000;
+ cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+ cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE;
+
+ return 0;
+}
+
+/* Specific video subsystem operation handlers */
+static const struct v4l2_subdev_video_ops ths8200_video_ops = {
+ .s_stream = ths8200_s_stream,
+ .s_dv_timings = ths8200_s_dv_timings,
+ .g_dv_timings = ths8200_g_dv_timings,
+ .enum_dv_timings = ths8200_enum_dv_timings,
+ .dv_timings_cap = ths8200_dv_timings_cap,
+};
+
+/* V4L2 top level operation handlers */
+static const struct v4l2_subdev_ops ths8200_ops = {
+ .core = &ths8200_core_ops,
+ .video = &ths8200_video_ops,
+};
+
+static int ths8200_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ths8200_state *state;
+ struct v4l2_subdev *sd;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &ths8200_ops);
+
+ state->chip_version = ths8200_read(sd, THS8200_VERSION);
+ v4l2_dbg(1, debug, sd, "chip version 0x%x\n", state->chip_version);
+
+ ths8200_core_init(sd);
+
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+ client->addr << 1, client->adapter->name);
+
+ return 0;
+}
+
+static int ths8200_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
+ client->addr << 1, client->adapter->name);
+
+ ths8200_s_power(sd, false);
+
+ v4l2_device_unregister_subdev(sd);
+
+ return 0;
+}
+
+static struct i2c_device_id ths8200_id[] = {
+ { "ths8200", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ths8200_id);
+
+static struct i2c_driver ths8200_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ths8200",
+ },
+ .probe = ths8200_probe,
+ .remove = ths8200_remove,
+ .id_table = ths8200_id,
+};
+
+module_i2c_driver(ths8200_driver);
diff --git a/drivers/media/i2c/ths8200_regs.h b/drivers/media/i2c/ths8200_regs.h
new file mode 100644
index 000000000000..6bc9fd1111db
--- /dev/null
+++ b/drivers/media/i2c/ths8200_regs.h
@@ -0,0 +1,161 @@
+/*
+ * ths8200 - Texas Instruments THS8200 video encoder driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef THS8200_REGS_H
+#define THS8200_REGS_H
+
+/* Register offset macros */
+#define THS8200_VERSION 0x02
+#define THS8200_CHIP_CTL 0x03
+#define THS8200_CSC_R11 0x04
+#define THS8200_CSC_R12 0x05
+#define THS8200_CSC_R21 0x06
+#define THS8200_CSC_R22 0x07
+#define THS8200_CSC_R31 0x08
+#define THS8200_CSC_R32 0x09
+#define THS8200_CSC_G11 0x0a
+#define THS8200_CSC_G12 0x0b
+#define THS8200_CSC_G21 0x0c
+#define THS8200_CSC_G22 0x0d
+#define THS8200_CSC_G31 0x0e
+#define THS8200_CSC_G32 0x0f
+#define THS8200_CSC_B11 0x10
+#define THS8200_CSC_B12 0x11
+#define THS8200_CSC_B21 0x12
+#define THS8200_CSC_B22 0x13
+#define THS8200_CSC_B31 0x14
+#define THS8200_CSC_B32 0x15
+#define THS8200_CSC_OFFS1 0x16
+#define THS8200_CSC_OFFS12 0x17
+#define THS8200_CSC_OFFS23 0x18
+#define THS8200_CSC_OFFS3 0x19
+#define THS8200_TST_CNTL1 0x1a
+#define THS8200_TST_CNTL2 0x1b
+#define THS8200_DATA_CNTL 0x1c
+#define THS8200_DTG1_Y_SYNC1_LSB 0x1d
+#define THS8200_DTG1_Y_SYNC2_LSB 0x1e
+#define THS8200_DTG1_Y_SYNC3_LSB 0x1f
+#define THS8200_DTG1_CBCR_SYNC1_LSB 0x20
+#define THS8200_DTG1_CBCR_SYNC2_LSB 0x21
+#define THS8200_DTG1_CBCR_SYNC3_LSB 0x22
+#define THS8200_DTG1_Y_SYNC_MSB 0x23
+#define THS8200_DTG1_CBCR_SYNC_MSB 0x24
+#define THS8200_DTG1_SPEC_A 0x25
+#define THS8200_DTG1_SPEC_B 0x26
+#define THS8200_DTG1_SPEC_C 0x27
+#define THS8200_DTG1_SPEC_D_LSB 0x28
+#define THS8200_DTG1_SPEC_D1 0x29
+#define THS8200_DTG1_SPEC_E_LSB 0x2a
+#define THS8200_DTG1_SPEC_DEH_MSB 0x2b
+#define THS8200_DTG1_SPEC_H_LSB 0x2c
+#define THS8200_DTG1_SPEC_I_MSB 0x2d
+#define THS8200_DTG1_SPEC_I_LSB 0x2e
+#define THS8200_DTG1_SPEC_K_LSB 0x2f
+#define THS8200_DTG1_SPEC_K_MSB 0x30
+#define THS8200_DTG1_SPEC_K1 0x31
+#define THS8200_DTG1_SPEC_G_LSB 0x32
+#define THS8200_DTG1_SPEC_G_MSB 0x33
+#define THS8200_DTG1_TOT_PIXELS_MSB 0x34
+#define THS8200_DTG1_TOT_PIXELS_LSB 0x35
+#define THS8200_DTG1_FLD_FLIP_LINECNT_MSB 0x36
+#define THS8200_DTG1_LINECNT_LSB 0x37
+#define THS8200_DTG1_MODE 0x38
+#define THS8200_DTG1_FRAME_FIELD_SZ_MSB 0x39
+#define THS8200_DTG1_FRAME_SZ_LSB 0x3a
+#define THS8200_DTG1_FIELD_SZ_LSB 0x3b
+#define THS8200_DTG1_VESA_CBAR_SIZE 0x3c
+#define THS8200_DAC_CNTL_MSB 0x3d
+#define THS8200_DAC1_CNTL_LSB 0x3e
+#define THS8200_DAC2_CNTL_LSB 0x3f
+#define THS8200_DAC3_CNTL_LSB 0x40
+#define THS8200_CSM_CLIP_GY_LOW 0x41
+#define THS8200_CSM_CLIP_BCB_LOW 0x42
+#define THS8200_CSM_CLIP_RCR_LOW 0x43
+#define THS8200_CSM_CLIP_GY_HIGH 0x44
+#define THS8200_CSM_CLIP_BCB_HIGH 0x45
+#define THS8200_CSM_CLIP_RCR_HIGH 0x46
+#define THS8200_CSM_SHIFT_GY 0x47
+#define THS8200_CSM_SHIFT_BCB 0x48
+#define THS8200_CSM_SHIFT_RCR 0x49
+#define THS8200_CSM_GY_CNTL_MULT_MSB 0x4a
+#define THS8200_CSM_MULT_BCB_RCR_MSB 0x4b
+#define THS8200_CSM_MULT_GY_LSB 0x4c
+#define THS8200_CSM_MULT_BCB_LSB 0x4d
+#define THS8200_CSM_MULT_RCR_LSB 0x4e
+#define THS8200_CSM_MULT_RCR_BCB_CNTL 0x4f
+#define THS8200_CSM_MULT_RCR_LSB 0x4e
+#define THS8200_DTG2_BP1_2_MSB 0x50
+#define THS8200_DTG2_BP3_4_MSB 0x51
+#define THS8200_DTG2_BP5_6_MSB 0x52
+#define THS8200_DTG2_BP7_8_MSB 0x53
+#define THS8200_DTG2_BP9_10_MSB 0x54
+#define THS8200_DTG2_BP11_12_MSB 0x55
+#define THS8200_DTG2_BP13_14_MSB 0x56
+#define THS8200_DTG2_BP15_16_MSB 0x57
+#define THS8200_DTG2_BP1_LSB 0x58
+#define THS8200_DTG2_BP2_LSB 0x59
+#define THS8200_DTG2_BP3_LSB 0x5a
+#define THS8200_DTG2_BP4_LSB 0x5b
+#define THS8200_DTG2_BP5_LSB 0x5c
+#define THS8200_DTG2_BP6_LSB 0x5d
+#define THS8200_DTG2_BP7_LSB 0x5e
+#define THS8200_DTG2_BP8_LSB 0x5f
+#define THS8200_DTG2_BP9_LSB 0x60
+#define THS8200_DTG2_BP10_LSB 0x61
+#define THS8200_DTG2_BP11_LSB 0x62
+#define THS8200_DTG2_BP12_LSB 0x63
+#define THS8200_DTG2_BP13_LSB 0x64
+#define THS8200_DTG2_BP14_LSB 0x65
+#define THS8200_DTG2_BP15_LSB 0x66
+#define THS8200_DTG2_BP16_LSB 0x67
+#define THS8200_DTG2_LINETYPE1 0x68
+#define THS8200_DTG2_LINETYPE2 0x69
+#define THS8200_DTG2_LINETYPE3 0x6a
+#define THS8200_DTG2_LINETYPE4 0x6b
+#define THS8200_DTG2_LINETYPE5 0x6c
+#define THS8200_DTG2_LINETYPE6 0x6d
+#define THS8200_DTG2_LINETYPE7 0x6e
+#define THS8200_DTG2_LINETYPE8 0x6f
+#define THS8200_DTG2_HLENGTH_LSB 0x70
+#define THS8200_DTG2_HLENGTH_LSB_HDLY_MSB 0x71
+#define THS8200_DTG2_HLENGTH_HDLY_LSB 0x72
+#define THS8200_DTG2_VLENGTH1_LSB 0x73
+#define THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB 0x74
+#define THS8200_DTG2_VDLY1_LSB 0x75
+#define THS8200_DTG2_VLENGTH2_LSB 0x76
+#define THS8200_DTG2_VLENGTH2_MSB_VDLY2_MSB 0x77
+#define THS8200_DTG2_VDLY2_LSB 0x78
+#define THS8200_DTG2_HS_IN_DLY_MSB 0x79
+#define THS8200_DTG2_HS_IN_DLY_LSB 0x7a
+#define THS8200_DTG2_VS_IN_DLY_MSB 0x7b
+#define THS8200_DTG2_VS_IN_DLY_LSB 0x7c
+#define THS8200_DTG2_PIXEL_CNT_MSB 0x7d
+#define THS8200_DTG2_PIXEL_CNT_LSB 0x7e
+#define THS8200_DTG2_LINE_CNT_MSB 0x7f
+#define THS8200_DTG2_LINE_CNT_LSB 0x80
+#define THS8200_DTG2_CNTL 0x82
+#define THS8200_CGMS_CNTL_HEADER 0x83
+#define THS8200_CGMS_PAYLOAD_MSB 0x84
+#define THS8200_CGMS_PAYLOAD_LSB 0x85
+#define THS8200_MISC_PPL_LSB 0x86
+#define THS8200_MISC_PPL_MSB 0x87
+#define THS8200_MISC_LPF_MSB 0x88
+#define THS8200_MISC_LPF_LSB 0x89
+
+#endif /* THS8200_REGS_H */
diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c
index 809a75a558ee..ef87f7b09ea2 100644
--- a/drivers/media/i2c/tlv320aic23b.c
+++ b/drivers/media/i2c/tlv320aic23b.c
@@ -162,7 +162,7 @@ static int tlv320aic23b_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -191,7 +191,6 @@ static int tlv320aic23b_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
v4l2_ctrl_handler_setup(&state->hdl);
@@ -205,7 +204,6 @@ static int tlv320aic23b_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index e0634c8b7e0b..d76c53a8f027 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -38,7 +38,6 @@
#include <media/tvaudio.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/i2c-addr.h>
@@ -1838,13 +1837,6 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
return 0;
}
-static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
-}
-
static int tvaudio_log_status(struct v4l2_subdev *sd)
{
struct CHIPSTATE *chip = to_state(sd);
@@ -1863,7 +1855,6 @@ static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {
static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
.log_status = tvaudio_log_status,
- .g_chip_ident = tvaudio_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1910,7 +1901,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
printk("\n");
}
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
sd = &chip->sd;
@@ -1930,7 +1921,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
}
if (desc->name == NULL) {
v4l2_dbg(1, debug, sd, "no matching chip description found\n");
- kfree(chip);
return -EIO;
}
v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
@@ -2001,7 +1991,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
int err = chip->hdl.error;
v4l2_ctrl_handler_free(&chip->hdl);
- kfree(chip);
return err;
}
/* set controls to the default values */
@@ -2044,7 +2033,6 @@ static int tvaudio_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&chip->hdl);
- kfree(chip);
return 0;
}
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index ab8f3fee7e94..9c6d66a9868f 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -39,7 +39,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-mediabus.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-of.h>
#include <media/v4l2-ctrls.h>
#include <media/tvp514x.h>
#include <media/media-entity.h>
@@ -123,6 +123,8 @@ struct tvp514x_decoder {
/* mc related members */
struct media_pad pad;
struct v4l2_mbus_framefmt format;
+
+ struct tvp514x_reg *int_seq;
};
/* TVP514x default register values */
@@ -543,8 +545,6 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
if (std_id == NULL)
return -EINVAL;
- *std_id = V4L2_STD_UNKNOWN;
-
/* To query the standard the TVP514x must power on the ADCs. */
if (!decoder->streaming) {
tvp514x_s_stream(sd, 1);
@@ -553,8 +553,10 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
/* query the current standard */
current_std = tvp514x_query_current_std(sd);
- if (current_std == STD_INVALID)
+ if (current_std == STD_INVALID) {
+ *std_id = V4L2_STD_UNKNOWN;
return 0;
+ }
input_sel = decoder->input;
@@ -595,10 +597,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
}
/* check whether signal is locked */
sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
- if (lock_mask != (sync_lock_status & lock_mask))
+ if (lock_mask != (sync_lock_status & lock_mask)) {
+ *std_id = V4L2_STD_UNKNOWN;
return 0; /* No input detected */
+ }
- *std_id = decoder->std_list[current_std].standard.id;
+ *std_id &= decoder->std_list[current_std].standard.id;
v4l2_dbg(1, debug, sd, "Current STD: %s\n",
decoder->std_list[current_std].standard.name);
@@ -862,7 +866,6 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
{
int err = 0;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tvp514x_decoder *decoder = to_decoder(sd);
if (decoder->streaming == enable)
@@ -882,11 +885,8 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
}
case 1:
{
- struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
- client->driver->id_table->driver_data;
-
/* Power Up Sequence */
- err = tvp514x_write_regs(sd, int_seq);
+ err = tvp514x_write_regs(sd, decoder->int_seq);
if (err) {
v4l2_err(sd, "Unable to turn on decoder\n");
return err;
@@ -1055,6 +1055,42 @@ static struct tvp514x_decoder tvp514x_dev = {
};
+static struct tvp514x_platform_data *
+tvp514x_get_pdata(struct i2c_client *client)
+{
+ struct tvp514x_platform_data *pdata;
+ struct v4l2_of_endpoint bus_cfg;
+ struct device_node *endpoint;
+ unsigned int flags;
+
+ if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+ return client->dev.platform_data;
+
+ endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ if (!endpoint)
+ return NULL;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+ flags = bus_cfg.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ pdata->hs_polarity = 1;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ pdata->vs_polarity = 1;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ pdata->clk_polarity = 1;
+
+done:
+ of_node_put(endpoint);
+ return pdata;
+}
+
/**
* tvp514x_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
@@ -1066,19 +1102,20 @@ static struct tvp514x_decoder tvp514x_dev = {
static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
+ struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client);
struct tvp514x_decoder *decoder;
struct v4l2_subdev *sd;
int ret;
+ if (pdata == NULL) {
+ dev_err(&client->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- if (!client->dev.platform_data) {
- v4l2_err(client, "No platform data!!\n");
- return -ENODEV;
- }
-
decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
@@ -1089,8 +1126,10 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
sizeof(tvp514x_reg_list_default));
+ decoder->int_seq = (struct tvp514x_reg *)id->driver_data;
+
/* Copy board specific information here */
- decoder->pdata = client->dev.platform_data;
+ decoder->pdata = pdata;
/**
* Fetch platform specific data, and configure the
@@ -1109,7 +1148,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Register with V4L2 layer as slave device */
sd = &decoder->sd;
v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
- strlcpy(sd->name, TVP514X_MODULE_NAME, sizeof(sd->name));
#if defined(CONFIG_MEDIA_CONTROLLER)
decoder->pad.flags = MEDIA_PAD_FL_SOURCE;
@@ -1120,7 +1158,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (ret < 0) {
v4l2_err(sd, "%s decoder driver failed to register !!\n",
sd->name);
- kfree(decoder);
return ret;
}
#endif
@@ -1231,8 +1268,20 @@ static const struct i2c_device_id tvp514x_id[] = {
MODULE_DEVICE_TABLE(i2c, tvp514x_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tvp514x_of_match[] = {
+ { .compatible = "ti,tvp5146", },
+ { .compatible = "ti,tvp5146m2", },
+ { .compatible = "ti,tvp5147", },
+ { .compatible = "ti,tvp5147m1", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, tvp514x_of_match);
+#endif
+
static struct i2c_driver tvp514x_driver = {
.driver = {
+ .of_match_table = of_match_ptr(tvp514x_of_match),
.owner = THIS_MODULE,
.name = TVP514X_MODULE_NAME,
},
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 485159a3c0b7..89c0b13463b7 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <media/v4l2-device.h>
#include <media/tvp5150.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include "tvp5150_reg.h"
@@ -727,13 +726,11 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* First tests should be against specific std */
- if (std == V4L2_STD_ALL) {
- fmt = VIDEO_STD_AUTO_SWITCH_BIT; /* Autodetect mode */
- } else if (std & V4L2_STD_NTSC_443) {
+ if (std == V4L2_STD_NTSC_443) {
fmt = VIDEO_STD_NTSC_4_43_BIT;
- } else if (std & V4L2_STD_PAL_M) {
+ } else if (std == V4L2_STD_PAL_M) {
fmt = VIDEO_STD_PAL_M_BIT;
- } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+ } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) {
fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
} else {
/* Then, test against generic ones */
@@ -1031,31 +1028,11 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- int rev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
- tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
- rev);
-}
-
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
int res;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
res = tvp5150_read(sd, reg->reg & 0xff);
if (res < 0) {
v4l2_err(sd, "%s: failed with error = %d\n", __func__, res);
@@ -1069,12 +1046,6 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
@@ -1098,7 +1069,6 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
.log_status = tvp5150_log_status,
.s_std = tvp5150_s_std,
.reset = tvp5150_reset,
- .g_chip_ident = tvp5150_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = tvp5150_g_register,
.s_register = tvp5150_s_register,
@@ -1152,10 +1122,9 @@ static int tvp5150_probe(struct i2c_client *c,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
- core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
- if (!core) {
+ core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
+ if (!core)
return -ENOMEM;
- }
sd = &core->sd;
v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
@@ -1166,7 +1135,7 @@ static int tvp5150_probe(struct i2c_client *c,
for (i = 0; i < 4; i++) {
res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
if (res < 0)
- goto free_core;
+ return res;
tvp5150_id[i] = res;
}
@@ -1209,7 +1178,7 @@ static int tvp5150_probe(struct i2c_client *c,
if (core->hdl.error) {
res = core->hdl.error;
v4l2_ctrl_handler_free(&core->hdl);
- goto free_core;
+ return res;
}
v4l2_ctrl_handler_setup(&core->hdl);
@@ -1225,10 +1194,6 @@ static int tvp5150_probe(struct i2c_client *c,
if (debug > 1)
tvp5150_log_status(sd);
return 0;
-
-free_core:
- kfree(core);
- return res;
}
static int tvp5150_remove(struct i2c_client *c)
@@ -1242,7 +1207,6 @@ static int tvp5150_remove(struct i2c_client *c)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(to_tvp5150(sd));
return 0;
}
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 027809cca5f5..a4e49483de6a 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -32,7 +32,6 @@
#include <linux/v4l2-dv-timings.h>
#include <media/tvp7002.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include "tvp7002_reg.h"
@@ -41,9 +40,6 @@ MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>");
MODULE_LICENSE("GPL");
-/* Module Name */
-#define TVP7002_MODULE_NAME "tvp7002"
-
/* I2C retry attempts */
#define I2C_RETRY_COUNT (5)
@@ -424,6 +420,7 @@ struct tvp7002 {
int streaming;
const struct tvp7002_timings_definition *current_timings;
+ struct media_pad pad;
};
/*
@@ -535,29 +532,6 @@ static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg,
}
/*
- * tvp7002_g_chip_ident() - Get chip identification number
- * @sd: ptr to v4l2_subdev struct
- * @chip: ptr to v4l2_dbg_chip_ident struct
- *
- * Obtains the chip's identification number.
- * Returns zero or -EINVAL if read operation fails.
- */
-static int tvp7002_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- u8 rev;
- int error;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- error = tvp7002_read(sd, TVP7002_CHIP_REV, &rev);
-
- if (error < 0)
- return error;
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev);
-}
-
-/*
* tvp7002_write_inittab() - Write initialization values
* @sd: ptr to v4l2_subdev struct
* @regs: ptr to i2c_reg_value struct
@@ -738,23 +712,17 @@ static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
*
* Get the value of a TVP7002 decoder device register.
* Returns zero when successful, -EINVAL if register read fails or
- * access to I2C client fails, -EPERM if the call is not allowed
- * by disabled CAP_SYS_ADMIN.
+ * access to I2C client fails.
*/
static int tvp7002_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 val;
int ret;
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
ret = tvp7002_read(sd, reg->reg & 0xff, &val);
reg->val = val;
+ reg->size = 1;
return ret;
}
@@ -764,19 +732,11 @@ static int tvp7002_g_register(struct v4l2_subdev *sd,
* @reg: ptr to v4l2_dbg_register struct
*
* Get the value of a TVP7002 decoder device register.
- * Returns zero when successful, -EINVAL if register read fails or
- * -EPERM if call not allowed.
+ * Returns zero when successful, -EINVAL if register read fails.
*/
static int tvp7002_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
return tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff);
}
#endif
@@ -880,9 +840,67 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
.s_ctrl = tvp7002_s_ctrl,
};
+/*
+ * tvp7002_enum_mbus_code() - Enum supported digital video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @code: pointer to subdev enum mbus code struct
+ *
+ * Enumerate supported digital video formats for pad.
+ */
+static int
+tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ /* Check requested format index is within range */
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_YUYV10_1X20;
+
+ return 0;
+}
+
+/*
+ * tvp7002_get_pad_format() - get video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @fmt: pointer to subdev format struct
+ *
+ * get video format for pad.
+ */
+static int
+tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tvp7002 *tvp7002 = to_tvp7002(sd);
+
+ fmt->format.code = V4L2_MBUS_FMT_YUYV10_1X20;
+ fmt->format.width = tvp7002->current_timings->timings.bt.width;
+ fmt->format.height = tvp7002->current_timings->timings.bt.height;
+ fmt->format.field = tvp7002->current_timings->scanmode;
+ fmt->format.colorspace = tvp7002->current_timings->color_space;
+
+ return 0;
+}
+
+/*
+ * tvp7002_set_pad_format() - set video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @fmt: pointer to subdev format struct
+ *
+ * set video format for pad.
+ */
+static int
+tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ return tvp7002_get_pad_format(sd, fh, fmt);
+}
+
/* V4L2 core operation handlers */
static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
- .g_chip_ident = tvp7002_g_chip_ident,
.log_status = tvp7002_log_status,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
@@ -910,10 +928,18 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
.enum_mbus_fmt = tvp7002_enum_mbus_fmt,
};
+/* media pad related operation handlers */
+static const struct v4l2_subdev_pad_ops tvp7002_pad_ops = {
+ .enum_mbus_code = tvp7002_enum_mbus_code,
+ .get_fmt = tvp7002_get_pad_format,
+ .set_fmt = tvp7002_set_pad_format,
+};
+
/* V4L2 top level operation handlers */
static const struct v4l2_subdev_ops tvp7002_ops = {
.core = &tvp7002_core_ops,
.video = &tvp7002_video_ops,
+ .pad = &tvp7002_pad_ops,
};
/*
@@ -993,19 +1019,34 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
timings = device->current_timings->timings;
error = tvp7002_s_dv_timings(sd, &timings);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ device->pad.flags = MEDIA_PAD_FL_SOURCE;
+ device->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ device->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+
+ error = media_entity_init(&device->sd.entity, 1, &device->pad, 0);
+ if (error < 0)
+ return error;
+#endif
+
v4l2_ctrl_handler_init(&device->hdl, 1);
v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
V4L2_CID_GAIN, 0, 255, 1, 0);
sd->ctrl_handler = &device->hdl;
if (device->hdl.error) {
- int err = device->hdl.error;
-
- v4l2_ctrl_handler_free(&device->hdl);
- return err;
+ error = device->hdl.error;
+ goto error;
}
v4l2_ctrl_handler_setup(&device->hdl);
return 0;
+
+error:
+ v4l2_ctrl_handler_free(&device->hdl);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&device->sd.entity);
+#endif
+ return error;
}
/*
@@ -1022,7 +1063,9 @@ static int tvp7002_remove(struct i2c_client *c)
v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
"on address 0x%x\n", c->addr);
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&device->sd.entity);
+#endif
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&device->hdl);
return 0;
diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c
index c5dc2c3bf2d7..f58607df6193 100644
--- a/drivers/media/i2c/tw2804.c
+++ b/drivers/media/i2c/tw2804.c
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#define TW2804_REG_AUTOGAIN 0x02
@@ -368,8 +367,7 @@ static int tw2804_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- state = kzalloc(sizeof(struct tw2804), GFP_KERNEL);
-
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -410,7 +408,6 @@ static int tw2804_probe(struct i2c_client *client,
err = state->hdl.error;
if (err) {
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
@@ -427,7 +424,6 @@ static int tw2804_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c
index 87880b19d8c3..285b759a5f7f 100644
--- a/drivers/media/i2c/tw9903.c
+++ b/drivers/media/i2c/tw9903.c
@@ -215,7 +215,7 @@ static int tw9903_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
- dec = kzalloc(sizeof(struct tw9903), GFP_KERNEL);
+ dec = devm_kzalloc(&client->dev, sizeof(*dec), GFP_KERNEL);
if (dec == NULL)
return -ENOMEM;
sd = &dec->sd;
@@ -233,7 +233,6 @@ static int tw9903_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(dec);
return err;
}
@@ -242,7 +241,6 @@ static int tw9903_probe(struct i2c_client *client,
if (write_regs(sd, initial_registers) < 0) {
v4l2_err(client, "error initializing TW9903\n");
- kfree(dec);
return -EINVAL;
}
@@ -255,7 +253,6 @@ static int tw9903_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&to_state(sd)->hdl);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c
index accd79e5a7fd..f6bef25bd9ce 100644
--- a/drivers/media/i2c/tw9906.c
+++ b/drivers/media/i2c/tw9906.c
@@ -183,7 +183,7 @@ static int tw9906_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
- dec = kzalloc(sizeof(struct tw9906), GFP_KERNEL);
+ dec = devm_kzalloc(&client->dev, sizeof(*dec), GFP_KERNEL);
if (dec == NULL)
return -ENOMEM;
sd = &dec->sd;
@@ -201,7 +201,6 @@ static int tw9906_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(dec);
return err;
}
@@ -210,7 +209,6 @@ static int tw9906_probe(struct i2c_client *client,
if (write_regs(sd, initial_registers) < 0) {
v4l2_err(client, "error initializing TW9906\n");
- kfree(dec);
return -EINVAL;
}
@@ -223,7 +221,6 @@ static int tw9906_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&to_state(sd)->hdl);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c
index 3af408556d27..081786d176d0 100644
--- a/drivers/media/i2c/uda1342.c
+++ b/drivers/media/i2c/uda1342.c
@@ -69,7 +69,7 @@ static int uda1342_probe(struct i2c_client *client,
dev_dbg(&client->dev, "initializing UDA1342 at address %d on %s\n",
client->addr, adapter->name);
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
@@ -89,7 +89,6 @@ static int uda1342_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
return 0;
}
diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c
index f0a09214c519..d248e6a12b8e 100644
--- a/drivers/media/i2c/upd64031a.c
+++ b/drivers/media/i2c/upd64031a.c
@@ -27,7 +27,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/upd64031a.h>
/* --------------------- read registers functions define -------------------- */
@@ -147,13 +146,6 @@ static int upd64031a_s_routing(struct v4l2_subdev *sd,
return upd64031a_s_frequency(sd, NULL);
}
-static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0);
-}
-
static int upd64031a_log_status(struct v4l2_subdev *sd)
{
v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
@@ -164,12 +156,6 @@ static int upd64031a_log_status(struct v4l2_subdev *sd)
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = upd64031a_read(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -177,12 +163,6 @@ static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
@@ -192,7 +172,6 @@ static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_re
static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
.log_status = upd64031a_log_status,
- .g_chip_ident = upd64031a_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = upd64031a_g_register,
.s_register = upd64031a_s_register,
@@ -230,7 +209,7 @@ static int upd64031a_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -249,7 +228,6 @@ static int upd64031a_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c
index 343e0215f74c..3a152ce7258a 100644
--- a/drivers/media/i2c/upd64083.c
+++ b/drivers/media/i2c/upd64083.c
@@ -27,7 +27,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/upd64083.h>
MODULE_DESCRIPTION("uPD64083 driver");
@@ -122,12 +121,6 @@ static int upd64083_s_routing(struct v4l2_subdev *sd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = upd64083_read(sd, reg->reg & 0xff);
reg->size = 1;
return 0;
@@ -135,24 +128,11 @@ static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
return 0;
}
#endif
-static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0);
-}
-
static int upd64083_log_status(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -169,7 +149,6 @@ static int upd64083_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops upd64083_core_ops = {
.log_status = upd64083_log_status,
- .g_chip_ident = upd64083_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = upd64083_g_register,
.s_register = upd64083_s_register,
@@ -202,7 +181,7 @@ static int upd64083_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -221,7 +200,6 @@ static int upd64083_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
index e71f139695af..6a3a3ff7ee6a 100644
--- a/drivers/media/i2c/vp27smpx.c
+++ b/drivers/media/i2c/vp27smpx.c
@@ -29,7 +29,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
MODULE_DESCRIPTION("vp27smpx driver");
MODULE_AUTHOR("Hans Verkuil");
@@ -112,13 +111,6 @@ static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0);
-}
-
static int vp27smpx_log_status(struct v4l2_subdev *sd)
{
struct vp27smpx_state *state = to_state(sd);
@@ -132,7 +124,6 @@ static int vp27smpx_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
.log_status = vp27smpx_log_status,
- .g_chip_ident = vp27smpx_g_chip_ident,
.s_std = vp27smpx_s_std,
};
@@ -169,7 +160,7 @@ static int vp27smpx_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -186,7 +177,6 @@ static int vp27smpx_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c
index 2f67b4c5c823..ece90df6a043 100644
--- a/drivers/media/i2c/vpx3220.c
+++ b/drivers/media/i2c/vpx3220.c
@@ -27,7 +27,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
@@ -49,7 +48,6 @@ struct vpx3220 {
unsigned char reg[255];
v4l2_std_id norm;
- int ident;
int input;
int enable;
};
@@ -297,7 +295,7 @@ static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
{
int res = V4L2_IN_ST_NO_SIGNAL, status;
- v4l2_std_id std = 0;
+ v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
status = vpx3220_fp_read(sd, 0x0f3);
@@ -314,19 +312,21 @@ static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pst
case 0x10:
case 0x14:
case 0x18:
- std = V4L2_STD_PAL;
+ std &= V4L2_STD_PAL;
break;
case 0x08:
- std = V4L2_STD_SECAM;
+ std &= V4L2_STD_SECAM;
break;
case 0x04:
case 0x0c:
case 0x1c:
- std = V4L2_STD_NTSC;
+ std &= V4L2_STD_NTSC;
break;
}
+ } else {
+ std = V4L2_STD_UNKNOWN;
}
if (pstd)
*pstd = std;
@@ -442,14 +442,6 @@ static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct vpx3220 *decoder = to_vpx3220(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
@@ -457,7 +449,6 @@ static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
};
static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
- .g_chip_ident = vpx3220_g_chip_ident,
.init = vpx3220_init,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
@@ -499,7 +490,7 @@ static int vpx3220_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (decoder == NULL)
return -ENOMEM;
sd = &decoder->sd;
@@ -521,7 +512,6 @@ static int vpx3220_probe(struct i2c_client *client,
int err = decoder->hdl.error;
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return err;
}
v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -529,7 +519,6 @@ static int vpx3220_probe(struct i2c_client *client,
ver = i2c_smbus_read_byte_data(client, 0x00);
pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
i2c_smbus_read_byte_data(client, 0x01);
- decoder->ident = V4L2_IDENT_VPX3220A;
if (ver == 0xec) {
switch (pn) {
case 0x4680:
@@ -537,11 +526,9 @@ static int vpx3220_probe(struct i2c_client *client,
break;
case 0x4260:
name = "vpx3216b";
- decoder->ident = V4L2_IDENT_VPX3216B;
break;
case 0x4280:
name = "vpx3214c";
- decoder->ident = V4L2_IDENT_VPX3214C;
break;
}
}
@@ -566,7 +553,7 @@ static int vpx3220_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
+
return 0;
}
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index f366fad6269e..25bdd9312fea 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -27,7 +27,6 @@
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
@@ -722,27 +721,9 @@ static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- int rev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
- | vs6624_read(sd, VS6624_FW_VSN_MINOR);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->val = vs6624_read(sd, reg->reg & 0xffff);
reg->size = 1;
return 0;
@@ -750,12 +731,6 @@ static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
return 0;
}
@@ -766,7 +741,6 @@ static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
};
static const struct v4l2_subdev_core_ops vs6624_core_ops = {
- .g_chip_ident = vs6624_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = vs6624_g_register,
.s_register = vs6624_s_register,
@@ -805,20 +779,18 @@ static int vs6624_probe(struct i2c_client *client,
if (ce == NULL)
return -EINVAL;
- ret = gpio_request(*ce, "VS6624 Chip Enable");
+ ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
+ "VS6624 Chip Enable");
if (ret) {
v4l_err(client, "failed to request GPIO %d\n", *ce);
return ret;
}
- gpio_direction_output(*ce, 1);
/* wait 100ms before any further i2c writes are performed */
mdelay(100);
- sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
- if (sensor == NULL) {
- gpio_free(*ce);
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
return -ENOMEM;
- }
sd = &sensor->sd;
v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
@@ -866,30 +838,22 @@ static int vs6624_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(sensor);
- gpio_free(*ce);
return err;
}
/* initialize the hardware to the default control values */
ret = v4l2_ctrl_handler_setup(hdl);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(hdl);
- kfree(sensor);
- gpio_free(*ce);
- }
return ret;
}
static int vs6624_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct vs6624 *sensor = to_vs6624(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- gpio_free(sensor->ce_pin);
- kfree(sensor);
return 0;
}
diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c
index 3bb99e93febe..3be73f6a40e9 100644
--- a/drivers/media/i2c/wm8739.c
+++ b/drivers/media/i2c/wm8739.c
@@ -29,7 +29,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("wm8739 driver");
@@ -160,13 +159,6 @@ static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
return 0;
}
-static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0);
-}
-
static int wm8739_log_status(struct v4l2_subdev *sd)
{
struct wm8739_state *state = to_state(sd);
@@ -184,7 +176,6 @@ static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
static const struct v4l2_subdev_core_ops wm8739_core_ops = {
.log_status = wm8739_log_status,
- .g_chip_ident = wm8739_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -220,7 +211,7 @@ static int wm8739_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct wm8739_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -237,7 +228,6 @@ static int wm8739_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
v4l2_ctrl_cluster(3, &state->volume);
@@ -271,7 +261,6 @@ static int wm8739_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c
index 27c27b4ae238..3f584a7d0781 100644
--- a/drivers/media/i2c/wm8775.c
+++ b/drivers/media/i2c/wm8775.c
@@ -33,7 +33,6 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/wm8775.h>
@@ -158,13 +157,6 @@ static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
-}
-
static int wm8775_log_status(struct v4l2_subdev *sd)
{
struct wm8775_state *state = to_state(sd);
@@ -188,7 +180,6 @@ static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {
static const struct v4l2_subdev_core_ops wm8775_core_ops = {
.log_status = wm8775_log_status,
- .g_chip_ident = wm8775_g_chip_ident,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -241,7 +232,7 @@ static int wm8775_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
sd = &state->sd;
@@ -261,7 +252,6 @@ static int wm8775_probe(struct i2c_client *client,
err = state->hdl.error;
if (err) {
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
@@ -319,7 +309,6 @@ static int wm8775_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 1957c0df08fd..d5a7a135f75d 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -142,6 +142,8 @@ static long __media_device_enum_links(struct media_device *mdev,
for (p = 0; p < entity->num_pads; p++) {
struct media_pad_desc pad;
+
+ memset(&pad, 0, sizeof(pad));
media_device_kpad_to_upad(&entity->pads[p], &pad);
if (copy_to_user(&links->pads[p], &pad, sizeof(pad)))
return -EFAULT;
@@ -159,6 +161,7 @@ static long __media_device_enum_links(struct media_device *mdev,
if (entity->links[l].source->entity != entity)
continue;
+ memset(&link, 0, sizeof(link));
media_device_kpad_to_upad(entity->links[l].source,
&link.source);
media_device_kpad_to_upad(entity->links[l].sink,
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index e1cd13283407..cb30ffbd5ba8 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -429,6 +429,56 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
}
EXPORT_SYMBOL_GPL(media_entity_create_link);
+void __media_entity_remove_links(struct media_entity *entity)
+{
+ unsigned int i;
+
+ for (i = 0; i < entity->num_links; i++) {
+ struct media_link *link = &entity->links[i];
+ struct media_entity *remote;
+ unsigned int r = 0;
+
+ if (link->source->entity == entity)
+ remote = link->sink->entity;
+ else
+ remote = link->source->entity;
+
+ while (r < remote->num_links) {
+ struct media_link *rlink = &remote->links[r];
+
+ if (rlink != link->reverse) {
+ r++;
+ continue;
+ }
+
+ if (link->source->entity == entity)
+ remote->num_backlinks--;
+
+ if (--remote->num_links == 0)
+ break;
+
+ /* Insert last entry in place of the dropped link. */
+ *rlink = remote->links[remote->num_links];
+ }
+ }
+
+ entity->num_links = 0;
+ entity->num_backlinks = 0;
+}
+EXPORT_SYMBOL_GPL(__media_entity_remove_links);
+
+void media_entity_remove_links(struct media_entity *entity)
+{
+ /* Do nothing if the entity is not registered. */
+ if (entity->parent == NULL)
+ return;
+
+ mutex_lock(&entity->parent->graph_mutex);
+ __media_entity_remove_links(entity);
+ mutex_unlock(&entity->parent->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_remove_links);
+
static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
{
int ret;
@@ -496,25 +546,17 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
mdev = source->parent;
- if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
- ret = mdev->link_notify(link->source, link->sink,
- MEDIA_LNK_FL_ENABLED);
+ if (mdev->link_notify) {
+ ret = mdev->link_notify(link, flags,
+ MEDIA_DEV_NOTIFY_PRE_LINK_CH);
if (ret < 0)
return ret;
}
ret = __media_entity_setup_link_notify(link, flags);
- if (ret < 0)
- goto err;
-
- if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
- mdev->link_notify(link->source, link->sink, 0);
-
- return 0;
-err:
- if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
- mdev->link_notify(link->source, link->sink, 0);
+ if (mdev->link_notify)
+ mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH);
return ret;
}
@@ -560,17 +602,16 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink)
EXPORT_SYMBOL_GPL(media_entity_find_link);
/**
- * media_entity_remote_source - Find the source pad at the remote end of a link
- * @pad: Sink pad at the local end of the link
+ * media_entity_remote_pad - Find the pad at the remote end of a link
+ * @pad: Pad at the local end of the link
*
- * Search for a remote source pad connected to the given sink pad by iterating
- * over all links originating or terminating at that pad until an enabled link
- * is found.
+ * Search for a remote pad connected to the given pad by iterating over all
+ * links originating or terminating at that pad until an enabled link is found.
*
* Return a pointer to the pad at the remote end of the first found enabled
* link, or NULL if no enabled link has been found.
*/
-struct media_pad *media_entity_remote_source(struct media_pad *pad)
+struct media_pad *media_entity_remote_pad(struct media_pad *pad)
{
unsigned int i;
@@ -590,4 +631,4 @@ struct media_pad *media_entity_remote_source(struct media_pad *pad)
return NULL;
}
-EXPORT_SYMBOL_GPL(media_entity_remote_source);
+EXPORT_SYMBOL_GPL(media_entity_remote_pad);
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index 06231b85e1a9..d12bd33f39cb 100644
--- a/drivers/media/parport/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
@@ -687,6 +687,7 @@ static int buffer_finish(struct vb2_buffer *vb)
parport_release(qcam->pdev);
mutex_unlock(&qcam->lock);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
if (len != size)
vb->state = VB2_BUF_STATE_ERROR;
vb2_set_plane_payload(vb, 0, len);
@@ -964,6 +965,7 @@ static struct qcam *qcam_init(struct parport *port)
q->drv_priv = qcam;
q->ops = &qcam_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
err = vb2_queue_init(q);
if (err < 0) {
v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index d4e2ed3f27e5..53196f1366f3 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -1,6 +1,7 @@
+if PCI && MEDIA_SUPPORT
+
menuconfig MEDIA_PCI_SUPPORT
bool "Media PCI Adapters"
- depends on PCI && MEDIA_SUPPORT
help
Enable media drivers for PCI/PCIe bus.
If you have such devices, say Y.
@@ -45,3 +46,4 @@ source "drivers/media/pci/ddbridge/Kconfig"
endif
endif #MEDIA_PCI_SUPPORT
+endif #PCI
diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c
index 44f8fb5f17ff..447afbd904a4 100644
--- a/drivers/media/pci/b2c2/flexcop-pci.c
+++ b/drivers/media/pci/b2c2/flexcop-pci.c
@@ -432,18 +432,7 @@ static struct pci_driver flexcop_pci_driver = {
.remove = flexcop_pci_remove,
};
-static int __init flexcop_pci_module_init(void)
-{
- return pci_register_driver(&flexcop_pci_driver);
-}
-
-static void __exit flexcop_pci_module_exit(void)
-{
- pci_unregister_driver(&flexcop_pci_driver);
-}
-
-module_init(flexcop_pci_module_init);
-module_exit(flexcop_pci_module_exit);
+module_pci_driver(flexcop_pci_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_NAME);
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index b7dc921e1b91..e564aac0aa30 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
"[yet another chipset flaw workaround]");
MODULE_PARM_DESC(latency,"pci latency timer");
MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
+MODULE_PARM_DESC(pll, "specify installed crystal (0=none, 28=28 MHz, 35=35 MHz, 14=14 MHz)");
MODULE_PARM_DESC(tuner,"specify installed tuner type");
MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
MODULE_PARM_DESC(audiodev, "specify audio device:\n"
@@ -2705,7 +2705,7 @@ struct tvcard bttv_tvcards[] = {
.has_radio = 1,
.has_remote = 1,
},
- [BTTV_BOARD_VD012] = {
+ [BTTV_BOARD_VD012] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012 (bt878)",
.video_inputs = 4,
@@ -2718,7 +2718,7 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
- [BTTV_BOARD_VD012_X1] = {
+ [BTTV_BOARD_VD012_X1] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012-X1 (bt878)",
.video_inputs = 4,
@@ -2731,7 +2731,7 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
- [BTTV_BOARD_VD012_X2] = {
+ [BTTV_BOARD_VD012_X2] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012-X2 (bt878)",
.video_inputs = 4,
@@ -2744,7 +2744,7 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
- [BTTV_BOARD_GEOVISION_GV800S] = {
+ [BTTV_BOARD_GEOVISION_GV800S] = {
/* Bruno Christo <bchristo@inf.ufsm.br>
*
* GeoVision GV-800(S) has 4 Conexant Fusion 878A:
@@ -2771,7 +2771,7 @@ struct tvcard bttv_tvcards[] = {
.no_tda7432 = 1,
.muxsel_hook = gv800s_muxsel,
},
- [BTTV_BOARD_GEOVISION_GV800S_SL] = {
+ [BTTV_BOARD_GEOVISION_GV800S_SL] = {
/* Bruno Christo <bchristo@inf.ufsm.br>
*
* GeoVision GV-800(S) has 4 Conexant Fusion 878A:
@@ -2808,6 +2808,7 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
+ /* ---- card 0xa0---------------------------------- */
[BTTV_BOARD_TVT_TD3116] = {
.name = "Tongwei Video Technology TD-3116",
.video_inputs = 16,
@@ -2825,6 +2826,35 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 3, 1, 0),
.tuner_type = TUNER_ABSENT,
},
+ [BTTV_BOARD_ADLINK_MPG24] = {
+ /* Adlink MPG24 */
+ .name = "Adlink MPG24",
+ .video_inputs = 1,
+ /* .audio_inputs= 1, */
+ .svhs = NO_SVHS,
+ .muxsel = MUXSEL(2, 2, 2, 2),
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_BT848_CAP_14] = {
+ .name = "Bt848 Capture 14MHz",
+ .video_inputs = 4,
+ .svhs = 2,
+ .muxsel = MUXSEL(2, 3, 1, 0),
+ .pll = PLL_14,
+ .tuner_type = TUNER_ABSENT,
+ },
+ [BTTV_BOARD_CYBERVISION_CV06] = {
+ .name = "CyberVision CV06 (SV)",
+ .video_inputs = 4,
+ /* .audio_inputs= 0, */
+ .svhs = NO_SVHS,
+ .muxsel = MUXSEL(2, 3, 1, 0),
+ .pll = PLL_28,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ },
};
@@ -3390,6 +3420,10 @@ void bttv_init_card2(struct bttv *btv)
btv->pll.pll_ifreq=35468950;
btv->pll.pll_crystal=BT848_IFORM_XT1;
}
+ if (PLL_14 == bttv_tvcards[btv->c.type].pll) {
+ btv->pll.pll_ifreq = 14318181;
+ btv->pll.pll_crystal = BT848_IFORM_XT0;
+ }
/* insmod options can override */
switch (pll[btv->c.nr]) {
case 0: /* none */
@@ -3409,6 +3443,12 @@ void bttv_init_card2(struct bttv *btv)
btv->pll.pll_ofreq = 0;
btv->pll.pll_crystal = BT848_IFORM_XT1;
break;
+ case 3: /* 14 MHz */
+ case 14:
+ btv->pll.pll_ifreq = 14318181;
+ btv->pll.pll_ofreq = 0;
+ btv->pll.pll_crystal = BT848_IFORM_XT0;
+ break;
}
}
btv->pll.pll_current = -1;
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index e7d088413411..c6532de0eac7 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -50,7 +50,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
#include <media/tvaudio.h>
#include <media/msp3400.h>
@@ -1761,9 +1760,9 @@ static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
struct bttv *btv = fh->btv;
if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
- *id = V4L2_STD_625_50;
+ *id &= V4L2_STD_625_50;
else
- *id = V4L2_STD_525_60;
+ *id &= V4L2_STD_525_60;
return 0;
}
@@ -1907,28 +1906,6 @@ static int bttv_log_status(struct file *file, void *f)
return 0;
}
-static int bttv_g_chip_ident(struct file *file, void *f, struct v4l2_dbg_chip_ident *chip)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match)) {
- chip->ident = btv->id;
- if (chip->ident == PCI_DEVICE_ID_FUSION879)
- chip->ident = V4L2_IDENT_BT879;
- }
- return 0;
- }
- if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
- chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
- /* TODO: is this correct? */
- return bttv_call_all_err(btv, core, g_chip_ident, chip);
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int bttv_g_register(struct file *file, void *f,
struct v4l2_dbg_register *reg)
@@ -1936,16 +1913,6 @@ static int bttv_g_register(struct file *file, void *f,
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (!v4l2_chip_match_host(&reg->match)) {
- /* TODO: subdev errors should not be ignored, this should become a
- subdev helper function. */
- bttv_call_all(btv, core, g_register, reg);
- return 0;
- }
-
/* bt848 has a 12-bit register space */
reg->reg &= 0xfff;
reg->val = btread(reg->reg);
@@ -1960,16 +1927,6 @@ static int bttv_s_register(struct file *file, void *f,
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (!v4l2_chip_match_host(&reg->match)) {
- /* TODO: subdev errors should not be ignored, this should become a
- subdev helper function. */
- bttv_call_all(btv, core, s_register, reg);
- return 0;
- }
-
/* bt848 has a 12-bit register space */
btwrite(reg->val, reg->reg & 0xfff);
@@ -3209,7 +3166,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_querystd = bttv_querystd,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = bttv_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = bttv_g_register,
.vidioc_s_register = bttv_s_register,
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index 6139ce26dc2c..df578efe03c9 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -185,6 +185,9 @@
#define BTTV_BOARD_PV183 0x9f
#define BTTV_BOARD_TVT_TD3116 0xa0
#define BTTV_BOARD_APOSONIC_WDVR 0xa1
+#define BTTV_BOARD_ADLINK_MPG24 0xa2
+#define BTTV_BOARD_BT848_CAP_14 0xa3
+#define BTTV_BOARD_CYBERVISION_CV06 0xa4
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
@@ -232,6 +235,7 @@ struct tvcard {
#define PLL_NONE 0
#define PLL_28 1
#define PLL_35 2
+#define PLL_14 3
/* i2c audio flags */
unsigned int no_msp34xx:1;
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index 38b1d64ffc27..c4890a430dc6 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -22,7 +22,6 @@
* 02110-1301, USA.
*/
-#include <media/v4l2-chip-ident.h>
#include "cx18-driver.h"
#include "cx18-io.h"
#include "cx18-cards.h"
@@ -1231,35 +1230,14 @@ static int cx18_av_log_status(struct v4l2_subdev *sd)
return 0;
}
-static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
-{
- return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
-}
-
-static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct cx18_av_state *state = to_cx18_av_state(sd);
-
- if (cx18_av_dbg_match(&chip->match)) {
- chip->ident = state->id;
- chip->revision = state->rev;
- }
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx18_av_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
- if (!cx18_av_dbg_match(&reg->match))
- return -EINVAL;
if ((reg->reg & 0x3) != 0)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->size = 4;
reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
return 0;
@@ -1270,12 +1248,8 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
- if (!cx18_av_dbg_match(&reg->match))
- return -EINVAL;
if ((reg->reg & 0x3) != 0)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
return 0;
}
@@ -1286,17 +1260,9 @@ static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
};
static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
- .g_chip_ident = cx18_av_g_chip_ident,
.log_status = cx18_av_log_status,
.load_fw = cx18_av_load_fw,
.reset = cx18_av_reset,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
- .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
- .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
- .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
- .queryctrl = v4l2_subdev_queryctrl,
- .querymenu = v4l2_subdev_querymenu,
.s_std = cx18_av_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx18_av_g_register,
@@ -1344,8 +1310,6 @@ int cx18_av_probe(struct cx18 *cx)
int err;
state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
- state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
- ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN;
state->vid_input = CX18_AV_COMPOSITE7;
state->aud_input = CX18_AV_AUDIO8;
diff --git a/drivers/media/pci/cx18/cx18-av-core.h b/drivers/media/pci/cx18/cx18-av-core.h
index e9c69d9c9e4a..4c559e86e340 100644
--- a/drivers/media/pci/cx18/cx18-av-core.h
+++ b/drivers/media/pci/cx18/cx18-av-core.h
@@ -104,7 +104,6 @@ struct cx18_av_state {
enum cx18_av_audio_input aud_input;
u32 audclk_freq;
int audmode;
- u32 id;
u32 rev;
int is_initialized;
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index aee7b6dacbfe..1110bcb14e2f 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -39,7 +39,6 @@
#include "cx18-cards.h"
#include "cx18-av-core.h"
#include <media/tveeprom.h>
-#include <media/v4l2-chip-ident.h>
u16 cx18_service2vbi(int type)
{
@@ -362,73 +361,18 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
return 0;
}
-static int cx18_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct cx18 *cx = fh2id(fh)->cx;
- int err = 0;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- switch (chip->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- switch (chip->match.addr) {
- case 0:
- chip->ident = V4L2_IDENT_CX23418;
- chip->revision = cx18_read_reg(cx, 0xC72028);
- break;
- case 1:
- /*
- * The A/V decoder is always present, but in the rare
- * case that the card doesn't have analog, we don't
- * use it. We find it w/o using the cx->sd_av pointer
- */
- cx18_call_hw(cx, CX18_HW_418_AV,
- core, g_chip_ident, chip);
- break;
- default:
- /*
- * Could return ident = V4L2_IDENT_UNKNOWN if we had
- * other host chips at higher addresses, but we don't
- */
- err = -EINVAL; /* per V4L2 spec */
- break;
- }
- break;
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
- cx18_call_all(cx, core, g_chip_ident, chip);
- break;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /*
- * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
- * to look if a chip is at the address with no driver. That's a
- * dangerous thing to do with EEPROMs anyway.
- */
- cx18_call_all(cx, core, g_chip_ident, chip);
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx18_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
struct cx18 *cx = fh2id(fh)->cx;
- if (v4l2_chip_match_host(&reg->match)) {
- if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
- return -EINVAL;
- reg->size = 4;
- reg->val = cx18_read_enc(cx, reg->reg);
- return 0;
- }
- /* FIXME - errors shouldn't be ignored */
- cx18_call_all(cx, core, g_register, reg);
+ if (reg->reg & 0x3)
+ return -EINVAL;
+ if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+ reg->size = 4;
+ reg->val = cx18_read_enc(cx, reg->reg);
return 0;
}
@@ -437,14 +381,11 @@ static int cx18_s_register(struct file *file, void *fh,
{
struct cx18 *cx = fh2id(fh)->cx;
- if (v4l2_chip_match_host(&reg->match)) {
- if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
- return -EINVAL;
- cx18_write_enc(cx, reg->val, reg->reg);
- return 0;
- }
- /* FIXME - errors shouldn't be ignored */
- cx18_call_all(cx, core, s_register, reg);
+ if (reg->reg & 0x3)
+ return -EINVAL;
+ if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+ cx18_write_enc(cx, reg->val, reg->reg);
return 0;
}
#endif
@@ -1162,7 +1103,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap,
.vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap,
.vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap,
- .vidioc_g_chip_ident = cx18_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = cx18_g_register,
.vidioc_s_register = cx18_s_register,
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 6dea11a7a858..e3fc2c71808a 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1217,8 +1217,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- call_all(dev, core, g_std, id);
-
+ *id = dev->tvnorm;
return 0;
}
@@ -1661,7 +1660,6 @@ static struct v4l2_file_operations mpeg_fops = {
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
- .vidioc_querystd = vidioc_g_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
@@ -1690,8 +1688,8 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_log_status = vidioc_log_status,
.vidioc_querymenu = vidioc_querymenu,
.vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_chip_ident = cx23885_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = cx23885_g_chip_info,
.vidioc_g_register = cx23885_g_register,
.vidioc_s_register = cx23885_s_register,
#endif
@@ -1702,7 +1700,6 @@ static struct video_device cx23885_mpeg_template = {
.fops = &mpeg_fops,
.ioctl_ops = &mpeg_ioctl_ops,
.tvnorms = CX23885_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
};
void cx23885_417_unregister(struct cx23885_dev *dev)
@@ -1735,7 +1732,7 @@ static struct video_device *cx23885_video_dev_alloc(
*vfd = *template;
snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
cx23885_boards[tsport->dev->board].name, type);
- vfd->parent = &pci->dev;
+ vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
return vfd;
}
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index acdb6d58db58..271d69d1ca8c 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -24,93 +24,21 @@
#include "cx23885.h"
#include "cx23885-ioctl.h"
-#include <media/v4l2-chip-ident.h>
-
-int cx23885_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int cx23885_g_chip_info(struct file *file, void *fh,
+ struct v4l2_dbg_chip_info *chip)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
- int err = 0;
- u8 rev;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- switch (chip->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- switch (chip->match.addr) {
- case 0:
- rev = cx_read(RDR_CFG2) & 0xff;
- switch (dev->pci->device) {
- case 0x8852:
- /* rev 0x04 could be '885 or '888. Pick '888. */
- if (rev == 0x04)
- chip->ident = V4L2_IDENT_CX23888;
- else
- chip->ident = V4L2_IDENT_CX23885;
- break;
- case 0x8880:
- if (rev == 0x0e || rev == 0x0f)
- chip->ident = V4L2_IDENT_CX23887;
- else
- chip->ident = V4L2_IDENT_CX23888;
- break;
- default:
- chip->ident = V4L2_IDENT_UNKNOWN;
- break;
- }
- chip->revision = (dev->pci->device << 16) | (rev << 8) |
- (dev->hwrevision & 0xff);
- break;
- case 1:
- if (dev->v4l_device != NULL) {
- chip->ident = V4L2_IDENT_CX23417;
- chip->revision = 0;
- }
- break;
- case 2:
- /*
- * The integrated IR controller on the CX23888 is
- * host chip 2. It may not be used/initialized or sd_ir
- * may be pointing at the cx25840 subdevice for the
- * IR controller on the CX23885. Thus we find it
- * without using the dev->sd_ir pointer.
- */
- call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident,
- chip);
- break;
- default:
- err = -EINVAL; /* per V4L2 spec */
- break;
- }
- break;
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
- call_all(dev, core, g_chip_ident, chip);
- break;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /*
- * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
- * to look if a chip is at the address with no driver. That's a
- * dangerous thing to do with EEPROMs anyway.
- */
- call_all(dev, core, g_chip_ident, chip);
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cx23885_g_host_register(struct cx23885_dev *dev,
- struct v4l2_dbg_register *reg)
-{
- if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+ if (chip->match.addr > 1)
return -EINVAL;
-
- reg->size = 4;
- reg->val = cx_read(reg->reg);
+ if (chip->match.addr == 1) {
+ if (dev->v4l_device == NULL)
+ return -EINVAL;
+ strlcpy(chip->name, "cx23417", sizeof(chip->name));
+ } else {
+ strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ }
return 0;
}
@@ -138,32 +66,16 @@ int cx23885_g_register(struct file *file, void *fh,
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
- switch (reg->match.addr) {
- case 0:
- return cx23885_g_host_register(dev, reg);
- case 1:
- return cx23417_g_register(dev, reg);
- default:
- break;
- }
- }
-
- /* FIXME - any error returns should not be ignored */
- call_all(dev, core, g_register, reg);
- return 0;
-}
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (reg->match.addr)
+ return cx23417_g_register(dev, reg);
-static int cx23885_s_host_register(struct cx23885_dev *dev,
- const struct v4l2_dbg_register *reg)
-{
if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
return -EINVAL;
- cx_write(reg->reg, reg->val);
+ reg->size = 4;
+ reg->val = cx_read(reg->reg);
return 0;
}
@@ -186,22 +98,15 @@ int cx23885_s_register(struct file *file, void *fh,
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
- switch (reg->match.addr) {
- case 0:
- return cx23885_s_host_register(dev, reg);
- case 1:
- return cx23417_s_register(dev, reg);
- default:
- break;
- }
- }
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (reg->match.addr)
+ return cx23417_s_register(dev, reg);
+
+ if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+ return -EINVAL;
- /* FIXME - any error returns should not be ignored */
- call_all(dev, core, s_register, reg);
+ cx_write(reg->reg, reg->val);
return 0;
}
#endif
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index a6080964a9ee..92d9f0774366 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -24,8 +24,8 @@
#ifndef _CX23885_IOCTL_H_
#define _CX23885_IOCTL_H_
-int cx23885_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip);
+int cx23885_g_chip_info(struct file *file, void *fh,
+ struct v4l2_dbg_chip_info *chip);
#ifdef CONFIG_VIDEO_ADV_DEBUG
int cx23885_g_register(struct file *file, void *fh,
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index ed08c89adde0..e33d1a7dfdd0 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -1254,8 +1254,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
dprintk(1, "%s()\n", __func__);
- call_all(dev, core, g_std, id);
-
+ *id = dev->tvnorm;
return 0;
}
@@ -1743,7 +1742,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
- .vidioc_querystd = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1757,8 +1755,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_g_chip_ident = cx23885_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = cx23885_g_chip_info,
.vidioc_g_register = cx23885_g_register,
.vidioc_s_register = cx23885_s_register,
#endif
@@ -1773,7 +1771,6 @@ static struct video_device cx23885_video_template = {
.fops = &video_fops,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = CX23885_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
};
static const struct v4l2_file_operations radio_fops = {
@@ -1822,7 +1819,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
cx23885_vbi_template = cx23885_video_template;
strcpy(cx23885_vbi_template.name, "cx23885-vbi");
- dev->tvnorm = cx23885_video_template.current_norm;
+ dev->tvnorm = V4L2_STD_NTSC_M;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index fa672fe41079..2c951dec2d33 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/rc-core.h>
#include "cx23885.h"
@@ -131,8 +130,6 @@ union cx23888_ir_fifo_rec {
struct cx23888_ir_state {
struct v4l2_subdev sd;
struct cx23885_dev *dev;
- u32 id;
- u32 rev;
struct v4l2_subdev_ir_parameters rx_params;
struct mutex rx_params_lock;
@@ -1086,23 +1083,6 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd)
return 0;
}
-static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match)
-{
- return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2;
-}
-
-static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct cx23888_ir_state *state = to_state(sd);
-
- if (cx23888_ir_dbg_match(&chip->match)) {
- chip->ident = state->id;
- chip->revision = state->rev;
- }
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx23888_ir_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -1110,14 +1090,10 @@ static int cx23888_ir_g_register(struct v4l2_subdev *sd,
struct cx23888_ir_state *state = to_state(sd);
u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
- if (!cx23888_ir_dbg_match(&reg->match))
- return -EINVAL;
if ((addr & 0x3) != 0)
return -EINVAL;
if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
reg->size = 4;
reg->val = cx23888_ir_read4(state->dev, addr);
return 0;
@@ -1129,21 +1105,16 @@ static int cx23888_ir_s_register(struct v4l2_subdev *sd,
struct cx23888_ir_state *state = to_state(sd);
u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
- if (!cx23888_ir_dbg_match(&reg->match))
- return -EINVAL;
if ((addr & 0x3) != 0)
return -EINVAL;
if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
cx23888_ir_write4(state->dev, addr, reg->val);
return 0;
}
#endif
static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
- .g_chip_ident = cx23888_ir_g_chip_ident,
.log_status = cx23888_ir_log_status,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx23888_ir_g_register,
@@ -1217,8 +1188,6 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
return -ENOMEM;
state->dev = dev;
- state->id = V4L2_IDENT_CX23888_IR;
- state->rev = 0;
sd = &state->sd;
v4l2_subdev_init(sd, &cx23888_ir_controller_ops);
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index a87a0e19593e..e18a7ace08b1 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -744,7 +744,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Some variants use a tda9874 and so need the tvaudio module. */
- .audio_chip = V4L2_IDENT_TVAUDIO,
+ .audio_chip = CX88_AUDIO_TVAUDIO,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -976,7 +976,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .audio_chip = V4L2_IDENT_WM8775,
+ .audio_chip = CX88_AUDIO_WM8775,
.i2sinputcntl = 2,
.input = {{
.type = CX88_VMUX_DVB,
@@ -1014,7 +1014,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .audio_chip = V4L2_IDENT_WM8775,
+ .audio_chip = CX88_AUDIO_WM8775,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
@@ -1376,7 +1376,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .audio_chip = V4L2_IDENT_WM8775,
+ .audio_chip = CX88_AUDIO_WM8775,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -1461,7 +1461,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .audio_chip = V4L2_IDENT_WM8775,
+ .audio_chip = CX88_AUDIO_WM8775,
/*
* gpio0 as reported by Mike Crash <mike AT mikecrash.com>
*/
@@ -1929,7 +1929,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .audio_chip = V4L2_IDENT_WM8775,
+ .audio_chip = CX88_AUDIO_WM8775,
/*
* GPIO0 (WINTV2000)
*
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index c8f3dcc579d4..ad59dc9235ae 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -1034,7 +1034,14 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
if (NULL == vfd)
return NULL;
*vfd = *template_;
+ /*
+ * The dev pointer of v4l2_device is NULL, instead we set the
+ * video_device dev_parent pointer to the correct PCI bus device.
+ * This driver is a rare example where there is one v4l2_device,
+ * but the video nodes have different parent (PCI) devices.
+ */
vfd->v4l2_dev = &core->v4l2_dev;
+ vfd->dev_parent = &pci->dev;
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index c7a9be1065c0..ecf21d9f1f34 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1353,26 +1353,14 @@ static int vidioc_s_frequency (struct file *file, void *priv,
return cx88_set_freq(core, f);
}
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- if (!v4l2_chip_match_host(&chip->match))
- return -EINVAL;
- chip->revision = 0;
- chip->ident = V4L2_IDENT_UNKNOWN;
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
/* cx2388x has a 24-bit register space */
- reg->val = cx_read(reg->reg & 0xffffff);
+ reg->val = cx_read(reg->reg & 0xfffffc);
reg->size = 4;
return 0;
}
@@ -1382,9 +1370,7 @@ static int vidioc_s_register (struct file *file, void *fh,
{
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- cx_write(reg->reg & 0xffffff, reg->val);
+ cx_write(reg->reg & 0xfffffc, reg->val);
return 0;
}
#endif
@@ -1578,7 +1564,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
@@ -1612,7 +1597,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
@@ -1643,7 +1627,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
@@ -1794,7 +1777,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
/* load and configure helper modules */
- if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+ if (core->board.audio_chip == CX88_AUDIO_WM8775) {
struct i2c_board_info wm8775_info = {
.type = "wm8775",
.addr = 0x36 >> 1,
@@ -1815,7 +1798,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
}
}
- if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
+ if (core->board.audio_chip == CX88_AUDIO_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index 51ce2c0e8bc1..afe0eaea81b4 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -30,7 +30,6 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
-#include <media/v4l2-chip-ident.h>
#include <media/cx2341x.h>
#include <media/videobuf-dvb.h>
#include <media/ir-kbd-i2c.h>
@@ -259,6 +258,11 @@ struct cx88_input {
unsigned int audioroute:4;
};
+enum cx88_audio_chip {
+ CX88_AUDIO_WM8775,
+ CX88_AUDIO_TVAUDIO,
+};
+
struct cx88_board {
const char *name;
unsigned int tuner_type;
@@ -269,7 +273,7 @@ struct cx88_board {
struct cx88_input input[MAX_CX88_INPUT];
struct cx88_input radio;
enum cx88_board_type mpeg;
- unsigned int audio_chip;
+ enum cx88_audio_chip audio_chip;
int num_frontends;
/* Used for I2S devices */
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 026767bed5cd..ab797fe466d2 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -1241,18 +1241,7 @@ static struct pci_driver dm1105_driver = {
.remove = dm1105_remove,
};
-static int __init dm1105_init(void)
-{
- return pci_register_driver(&dm1105_driver);
-}
-
-static void __exit dm1105_exit(void)
-{
- pci_unregister_driver(&dm1105_driver);
-}
-
-module_init(dm1105_init);
-module_exit(dm1105_exit);
+module_pci_driver(dm1105_driver);
MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index b809bc868a9f..c08ae3eb9554 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -58,7 +58,6 @@
#include <linux/dma-mapping.h>
#include <media/tveeprom.h>
#include <media/saa7115.h>
-#include <media/v4l2-chip-ident.h>
#include "tuner-xc2028.h"
/* If you have already X v4l cards, then set this to X. This way
@@ -968,15 +967,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
}
if (hw & IVTV_HW_SAA711X) {
- struct v4l2_dbg_chip_ident v;
-
/* determine the exact saa711x model */
itv->hw_flags &= ~IVTV_HW_SAA711X;
- v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
- strlcpy(v.match.name, "saa7115", sizeof(v.match.name));
- ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
- if (v.ident == V4L2_IDENT_SAA7114) {
+ if (strstr(itv->sd_video->name, "saa7114")) {
itv->hw_flags |= IVTV_HW_SAA7114;
/* VBI is not yet supported by the saa7114 driver. */
itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE);
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 9cbbce0eaedc..807b275a847e 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -34,7 +34,6 @@
#include "ivtv-cards.h"
#include <media/saa7127.h>
#include <media/tveeprom.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-event.h>
#include <linux/dvb/audio.h>
@@ -692,31 +691,13 @@ static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f
return ret;
}
-static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
-{
- struct ivtv *itv = fh2id(fh)->itv;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match))
- chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
- return 0;
- }
- if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
- chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
- /* TODO: is this correct? */
- return ivtv_call_all_err(itv, core, g_chip_ident, chip);
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val)
{
volatile u8 __iomem *reg_start;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ if (reg & 0x3)
+ return -EINVAL;
if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
reg_start = itv->reg_mem - IVTV_REG_OFFSET;
else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET &&
@@ -738,29 +719,16 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register
{
struct ivtv *itv = fh2id(fh)->itv;
- if (v4l2_chip_match_host(&reg->match)) {
- reg->size = 4;
- return ivtv_itvc(itv, true, reg->reg, &reg->val);
- }
- /* TODO: subdev errors should not be ignored, this should become a
- subdev helper function. */
- ivtv_call_all(itv, core, g_register, reg);
- return 0;
+ reg->size = 4;
+ return ivtv_itvc(itv, true, reg->reg, &reg->val);
}
static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
{
struct ivtv *itv = fh2id(fh)->itv;
+ u64 val = reg->val;
- if (v4l2_chip_match_host(&reg->match)) {
- u64 val = reg->val;
-
- return ivtv_itvc(itv, false, reg->reg, &val);
- }
- /* TODO: subdev errors should not be ignored, this should become a
- subdev helper function. */
- ivtv_call_all(itv, core, s_register, reg);
- return 0;
+ return ivtv_itvc(itv, false, reg->reg, &val);
}
#endif
@@ -1914,7 +1882,6 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
.vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay,
.vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out,
.vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap,
- .vidioc_g_chip_ident = ivtv_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = ivtv_g_register,
.vidioc_s_register = ivtv_s_register,
diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c
index 6fe9fe5293dc..104914a5bf06 100644
--- a/drivers/media/pci/mantis/hopper_cards.c
+++ b/drivers/media/pci/mantis/hopper_cards.c
@@ -260,18 +260,7 @@ static struct pci_driver hopper_pci_driver = {
.remove = hopper_pci_remove,
};
-static int hopper_init(void)
-{
- return pci_register_driver(&hopper_pci_driver);
-}
-
-static void hopper_exit(void)
-{
- return pci_unregister_driver(&hopper_pci_driver);
-}
-
-module_init(hopper_init);
-module_exit(hopper_exit);
+module_pci_driver(hopper_pci_driver);
MODULE_DESCRIPTION("HOPPER driver");
MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c
index 932a0d73a7f8..801fc55b6167 100644
--- a/drivers/media/pci/mantis/mantis_cards.c
+++ b/drivers/media/pci/mantis/mantis_cards.c
@@ -290,18 +290,7 @@ static struct pci_driver mantis_pci_driver = {
.remove = mantis_pci_remove,
};
-static int mantis_init(void)
-{
- return pci_register_driver(&mantis_pci_driver);
-}
-
-static void mantis_exit(void)
-{
- return pci_unregister_driver(&mantis_pci_driver);
-}
-
-module_init(mantis_init);
-module_exit(mantis_exit);
+module_pci_driver(mantis_pci_driver);
MODULE_DESCRIPTION("MANTIS driver");
MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
index 07aa887a4b4a..07a20748b707 100644
--- a/drivers/media/pci/mantis/mantis_vp1041.c
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
@@ -273,7 +273,7 @@ struct stb0899_config vp1041_stb0899_config = {
.demod_address = 0x68, /* 0xd0 >> 1 */
.xtal_freq = 27000000,
- .inversion = IQ_SWAP_ON, /* 1 */
+ .inversion = IQ_SWAP_ON,
.lo_clk = 76500000,
.hi_clk = 99000000,
diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c
index 2290faee5852..493828500055 100644
--- a/drivers/media/pci/pluto2/pluto2.c
+++ b/drivers/media/pci/pluto2/pluto2.c
@@ -796,18 +796,7 @@ static struct pci_driver pluto2_driver = {
.remove = pluto2_remove,
};
-static int __init pluto2_init(void)
-{
- return pci_register_driver(&pluto2_driver);
-}
-
-static void __exit pluto2_exit(void)
-{
- pci_unregister_driver(&pluto2_driver);
-}
-
-module_init(pluto2_init);
-module_exit(pluto2_exit);
+module_pci_driver(pluto2_driver);
MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
MODULE_DESCRIPTION("Pluto2 driver");
diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c
index e9211086df49..75ce14229e03 100644
--- a/drivers/media/pci/pt1/pt1.c
+++ b/drivers/media/pci/pt1/pt1.c
@@ -1225,20 +1225,7 @@ static struct pci_driver pt1_driver = {
.id_table = pt1_id_table,
};
-
-static int __init pt1_init(void)
-{
- return pci_register_driver(&pt1_driver);
-}
-
-
-static void __exit pt1_cleanup(void)
-{
- pci_unregister_driver(&pt1_driver);
-}
-
-module_init(pt1_init);
-module_exit(pt1_cleanup);
+module_pci_driver(pt1_driver);
MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
diff --git a/drivers/media/pci/saa7134/saa6752hs.c b/drivers/media/pci/saa7134/saa6752hs.c
index f147b05bd860..8ac4b1f2322d 100644
--- a/drivers/media/pci/saa7134/saa6752hs.c
+++ b/drivers/media/pci/saa7134/saa6752hs.c
@@ -34,8 +34,8 @@
#include <linux/types.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -92,7 +92,12 @@ static const struct v4l2_format v4l2_format_table[] =
struct saa6752hs_state {
struct v4l2_subdev sd;
- int chip;
+ struct v4l2_ctrl_handler hdl;
+ struct { /* video bitrate mode control cluster */
+ struct v4l2_ctrl *video_bitrate_mode;
+ struct v4l2_ctrl *video_bitrate;
+ struct v4l2_ctrl *video_bitrate_peak;
+ };
u32 revision;
int has_ac3;
struct saa6752hs_mpeg_params params;
@@ -362,316 +367,72 @@ static int saa6752hs_set_bitrate(struct i2c_client *client,
return 0;
}
-
-static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
- struct v4l2_ext_control *ctrl)
+static int saa6752hs_try_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct saa6752hs_state *h =
+ container_of(ctrl->handler, struct saa6752hs_state, hdl);
+
switch (ctrl->id) {
- case V4L2_CID_MPEG_STREAM_TYPE:
- ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
- break;
- case V4L2_CID_MPEG_STREAM_PID_PMT:
- ctrl->value = params->ts_pid_pmt;
- break;
- case V4L2_CID_MPEG_STREAM_PID_AUDIO:
- ctrl->value = params->ts_pid_audio;
- break;
- case V4L2_CID_MPEG_STREAM_PID_VIDEO:
- ctrl->value = params->ts_pid_video;
- break;
- case V4L2_CID_MPEG_STREAM_PID_PCR:
- ctrl->value = params->ts_pid_pcr;
- break;
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- ctrl->value = params->au_encoding;
- break;
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- ctrl->value = params->au_l2_bitrate;
- break;
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- if (!has_ac3)
- return -EINVAL;
- ctrl->value = params->au_ac3_bitrate;
- break;
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
- break;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- ctrl->value = params->vi_aspect;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- ctrl->value = params->vi_bitrate * 1000;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- ctrl->value = params->vi_bitrate_peak * 1000;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- ctrl->value = params->vi_bitrate_mode;
+ /* peak bitrate shall be >= normal bitrate */
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ h->video_bitrate_peak->val < h->video_bitrate->val)
+ h->video_bitrate_peak->val = h->video_bitrate->val;
break;
- default:
- return -EINVAL;
}
return 0;
}
-static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
- struct v4l2_ext_control *ctrl, int set)
+static int saa6752hs_s_ctrl(struct v4l2_ctrl *ctrl)
{
- int old = 0, new;
+ struct saa6752hs_state *h =
+ container_of(ctrl->handler, struct saa6752hs_state, hdl);
+ struct saa6752hs_mpeg_params *params = &h->params;
- new = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_MPEG_STREAM_TYPE:
- old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
- if (set && new != old)
- return -ERANGE;
- new = old;
break;
case V4L2_CID_MPEG_STREAM_PID_PMT:
- old = params->ts_pid_pmt;
- if (set && new > MPEG_PID_MAX)
- return -ERANGE;
- if (new > MPEG_PID_MAX)
- new = MPEG_PID_MAX;
- params->ts_pid_pmt = new;
+ params->ts_pid_pmt = ctrl->val;
break;
case V4L2_CID_MPEG_STREAM_PID_AUDIO:
- old = params->ts_pid_audio;
- if (set && new > MPEG_PID_MAX)
- return -ERANGE;
- if (new > MPEG_PID_MAX)
- new = MPEG_PID_MAX;
- params->ts_pid_audio = new;
+ params->ts_pid_audio = ctrl->val;
break;
case V4L2_CID_MPEG_STREAM_PID_VIDEO:
- old = params->ts_pid_video;
- if (set && new > MPEG_PID_MAX)
- return -ERANGE;
- if (new > MPEG_PID_MAX)
- new = MPEG_PID_MAX;
- params->ts_pid_video = new;
+ params->ts_pid_video = ctrl->val;
break;
case V4L2_CID_MPEG_STREAM_PID_PCR:
- old = params->ts_pid_pcr;
- if (set && new > MPEG_PID_MAX)
- return -ERANGE;
- if (new > MPEG_PID_MAX)
- new = MPEG_PID_MAX;
- params->ts_pid_pcr = new;
+ params->ts_pid_pcr = ctrl->val;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
- old = params->au_encoding;
- if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
- (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
- return -ERANGE;
- params->au_encoding = new;
+ params->au_encoding = ctrl->val;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- old = params->au_l2_bitrate;
- if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
- new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
- return -ERANGE;
- if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
- new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
- else
- new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
- params->au_l2_bitrate = new;
+ params->au_l2_bitrate = ctrl->val;
break;
case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- if (!has_ac3)
- return -EINVAL;
- old = params->au_ac3_bitrate;
- if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
- new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
- return -ERANGE;
- if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
- new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
- else
- new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
- params->au_ac3_bitrate = new;
+ params->au_ac3_bitrate = ctrl->val;
break;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
- if (set && new != old)
- return -ERANGE;
- new = old;
break;
case V4L2_CID_MPEG_VIDEO_ENCODING:
- old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
- if (set && new != old)
- return -ERANGE;
- new = old;
break;
case V4L2_CID_MPEG_VIDEO_ASPECT:
- old = params->vi_aspect;
- if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
- new != V4L2_MPEG_VIDEO_ASPECT_4x3)
- return -ERANGE;
- if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
- new = V4L2_MPEG_VIDEO_ASPECT_4x3;
- params->vi_aspect = new;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- old = params->vi_bitrate * 1000;
- new = 1000 * (new / 1000);
- if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
- return -ERANGE;
- if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
- new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
- params->vi_bitrate = new / 1000;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- old = params->vi_bitrate_peak * 1000;
- new = 1000 * (new / 1000);
- if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
- return -ERANGE;
- if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
- new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
- params->vi_bitrate_peak = new / 1000;
+ params->vi_aspect = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- old = params->vi_bitrate_mode;
- params->vi_bitrate_mode = new;
+ params->vi_bitrate_mode = ctrl->val;
+ params->vi_bitrate = h->video_bitrate->val / 1000;
+ params->vi_bitrate_peak = h->video_bitrate_peak->val / 1000;
+ v4l2_ctrl_activate(h->video_bitrate_peak,
+ ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
break;
default:
return -EINVAL;
}
- ctrl->value = new;
return 0;
}
-
-static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
-{
- struct saa6752hs_state *h = to_state(sd);
- struct saa6752hs_mpeg_params *params = &h->params;
- int err;
-
- switch (qctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
-
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_L2_BITRATE_256K,
- V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
- V4L2_MPEG_AUDIO_L2_BITRATE_256K);
-
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- if (!h->has_ac3)
- return -EINVAL;
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
- V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
-
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
-
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
-
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_ASPECT_4x3,
- V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
- V4L2_MPEG_VIDEO_ASPECT_4x3);
-
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
- if (err == 0 &&
- params->vi_bitrate_mode ==
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
- qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return err;
-
- case V4L2_CID_MPEG_STREAM_TYPE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
- V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
- V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
-
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
- case V4L2_CID_MPEG_STREAM_PID_PMT:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
- case V4L2_CID_MPEG_STREAM_PID_AUDIO:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
- case V4L2_CID_MPEG_STREAM_PID_VIDEO:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
- case V4L2_CID_MPEG_STREAM_PID_PCR:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
-
- default:
- break;
- }
- return -EINVAL;
-}
-
-static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
-{
- static const u32 mpeg_audio_encoding[] = {
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- V4L2_CTRL_MENU_IDS_END
- };
- static const u32 mpeg_audio_ac3_encoding[] = {
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- V4L2_MPEG_AUDIO_ENCODING_AC3,
- V4L2_CTRL_MENU_IDS_END
- };
- static u32 mpeg_audio_l2_bitrate[] = {
- V4L2_MPEG_AUDIO_L2_BITRATE_256K,
- V4L2_MPEG_AUDIO_L2_BITRATE_384K,
- V4L2_CTRL_MENU_IDS_END
- };
- static u32 mpeg_audio_ac3_bitrate[] = {
- V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
- V4L2_CTRL_MENU_IDS_END
- };
- struct saa6752hs_state *h = to_state(sd);
- struct v4l2_queryctrl qctrl;
- int err;
-
- qctrl.id = qmenu->id;
- err = saa6752hs_queryctrl(sd, &qctrl);
- if (err)
- return err;
- switch (qmenu->id) {
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return v4l2_ctrl_query_menu_valid_items(qmenu,
- mpeg_audio_l2_bitrate);
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- if (!h->has_ac3)
- return -EINVAL;
- return v4l2_ctrl_query_menu_valid_items(qmenu,
- mpeg_audio_ac3_bitrate);
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return v4l2_ctrl_query_menu_valid_items(qmenu,
- h->has_ac3 ? mpeg_audio_ac3_encoding :
- mpeg_audio_encoding);
- }
- return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
-}
-
static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
{
unsigned char buf[9], buf2[4];
@@ -793,58 +554,6 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
return 0;
}
-static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
-{
- struct saa6752hs_state *h = to_state(sd);
- struct saa6752hs_mpeg_params params;
- int i;
-
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- params = h->params;
- for (i = 0; i < ctrls->count; i++) {
- int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
-
- if (err) {
- ctrls->error_idx = i;
- return err;
- }
- }
- if (set)
- h->params = params;
- return 0;
-}
-
-static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
- return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
-}
-
-static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
- return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
-}
-
-static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
- struct saa6752hs_state *h = to_state(sd);
- int i;
-
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- for (i = 0; i < ctrls->count; i++) {
- int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
-
- if (err) {
- ctrls->error_idx = i;
- return err;
- }
- }
- return 0;
-}
-
static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
@@ -859,25 +568,11 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
return 0;
}
-static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
- struct saa6752hs_state *h = to_state(sd);
int dist_352, dist_480, dist_720;
- if (f->code != V4L2_MBUS_FMT_FIXED)
- return -EINVAL;
-
- /*
- FIXME: translate and round width/height into EMPRESS
- subsample type:
-
- type | PAL | NTSC
- ---------------------------
- SIF | 352x288 | 352x240
- 1/2 D1 | 352x576 | 352x480
- 2/3 D1 | 480x576 | 480x480
- D1 | 720x576 | 720x480
- */
+ f->code = V4L2_MBUS_FMT_FIXED;
dist_352 = abs(f->width - 352);
dist_480 = abs(f->width - 480);
@@ -885,59 +580,82 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
if (dist_720 < dist_480) {
f->width = 720;
f->height = 576;
- h->video_format = SAA6752HS_VF_D1;
} else if (dist_480 < dist_352) {
f->width = 480;
f->height = 576;
- h->video_format = SAA6752HS_VF_2_3_D1;
} else {
f->width = 352;
- if (abs(f->height - 576) <
- abs(f->height - 288)) {
+ if (abs(f->height - 576) < abs(f->height - 288))
f->height = 576;
- h->video_format = SAA6752HS_VF_1_2_D1;
- } else {
+ else
f->height = 288;
- h->video_format = SAA6752HS_VF_SIF;
- }
}
f->field = V4L2_FIELD_INTERLACED;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
-static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
- h->standard = std;
+ if (f->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
+
+ /*
+ FIXME: translate and round width/height into EMPRESS
+ subsample type:
+
+ type | PAL | NTSC
+ ---------------------------
+ SIF | 352x288 | 352x240
+ 1/2 D1 | 352x576 | 352x480
+ 2/3 D1 | 480x576 | 480x480
+ D1 | 720x576 | 720x480
+ */
+
+ saa6752hs_try_mbus_fmt(sd, f);
+ if (f->width == 720)
+ h->video_format = SAA6752HS_VF_D1;
+ else if (f->width == 480)
+ h->video_format = SAA6752HS_VF_2_3_D1;
+ else if (f->height == 576)
+ h->video_format = SAA6752HS_VF_1_2_D1;
+ else
+ h->video_format = SAA6752HS_VF_SIF;
return 0;
}
-static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct saa6752hs_state *h = to_state(sd);
- return v4l2_chip_ident_i2c_client(client,
- chip, h->chip, h->revision);
+ h->standard = std;
+ return 0;
}
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
+ .try_ctrl = saa6752hs_try_ctrl,
+ .s_ctrl = saa6752hs_s_ctrl,
+};
+
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
- .g_chip_ident = saa6752hs_g_chip_ident,
.init = saa6752hs_init,
- .queryctrl = saa6752hs_queryctrl,
- .querymenu = saa6752hs_querymenu,
- .g_ext_ctrls = saa6752hs_g_ext_ctrls,
- .s_ext_ctrls = saa6752hs_s_ext_ctrls,
- .try_ext_ctrls = saa6752hs_try_ext_ctrls,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
.s_std = saa6752hs_s_std,
};
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
.s_mbus_fmt = saa6752hs_s_mbus_fmt,
+ .try_mbus_fmt = saa6752hs_try_mbus_fmt,
.g_mbus_fmt = saa6752hs_g_mbus_fmt,
};
@@ -951,6 +669,7 @@ static int saa6752hs_probe(struct i2c_client *client,
{
struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
u8 addr = 0x13;
u8 data[12];
@@ -963,15 +682,88 @@ static int saa6752hs_probe(struct i2c_client *client,
i2c_master_send(client, &addr, 1);
i2c_master_recv(client, data, sizeof(data));
- h->chip = V4L2_IDENT_SAA6752HS;
h->revision = (data[8] << 8) | data[9];
h->has_ac3 = 0;
if (h->revision == 0x0206) {
- h->chip = V4L2_IDENT_SAA6752HS_AC3;
h->has_ac3 = 1;
- v4l_info(client, "support AC-3\n");
+ v4l_info(client, "supports AC-3\n");
}
h->params = param_defaults;
+
+ hdl = &h->hdl;
+ v4l2_ctrl_handler_init(hdl, 14);
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ 0x0d, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+ ~((1 << V4L2_MPEG_AUDIO_L2_BITRATE_256K) |
+ (1 << V4L2_MPEG_AUDIO_L2_BITRATE_384K)),
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+ if (h->has_ac3)
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+ ~((1 << V4L2_MPEG_AUDIO_AC3_BITRATE_256K) |
+ (1 << V4L2_MPEG_AUDIO_AC3_BITRATE_384K)),
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ ~(1 << V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000),
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ ~(1 << V4L2_MPEG_VIDEO_ENCODING_MPEG_2),
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_MPEG_VIDEO_ASPECT_16x9, 0x01,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+ h->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 1000000, 27000000, 1000, 8000000);
+
+ v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ ~(1 << V4L2_MPEG_STREAM_TYPE_MPEG2_TS),
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+ h->video_bitrate_mode = v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ h->video_bitrate = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE, 1000000, 27000000, 1000, 6000000);
+ v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_PID_PMT, 0, (1 << 14) - 1, 1, 16);
+ v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_PID_AUDIO, 0, (1 << 14) - 1, 1, 260);
+ v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_PID_VIDEO, 0, (1 << 14) - 1, 1, 256);
+ v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_PID_PCR, 0, (1 << 14) - 1, 1, 259);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(h);
+ return err;
+ }
+ v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
+ v4l2_ctrl_handler_setup(hdl);
h->standard = 0; /* Assume 625 input lines */
return 0;
}
@@ -981,6 +773,7 @@ static int saa6752hs_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&to_state(sd)->hdl);
kfree(to_state(sd));
return 0;
}
@@ -1002,11 +795,3 @@ static struct i2c_driver saa6752hs_driver = {
};
module_i2c_driver(saa6752hs_driver);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 66a70814004c..3022eb2a7925 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -28,7 +28,6 @@
#include <media/saa6752hs.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
/* ------------------------------------------------------------------ */
@@ -213,7 +212,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
strlcpy(f->description, "MPEG TS", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
-
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
return 0;
}
@@ -228,6 +227,8 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -244,6 +245,8 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -252,9 +255,16 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -413,21 +423,6 @@ static int empress_querymenu(struct file *file, void *priv,
return saa_call_empress(dev, core, querymenu, c);
}
-static int empress_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct saa7134_dev *dev = file->private_data;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
- !strcmp(chip->match.name, "saa6752hs"))
- return saa_call_empress(dev, core, g_chip_ident, chip);
- if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
- return saa_call_empress(dev, core, g_chip_ident, chip);
- return -EINVAL;
-}
-
static int empress_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = file->private_data;
@@ -475,7 +470,6 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_querymenu = empress_querymenu,
.vidioc_g_ctrl = empress_g_ctrl,
.vidioc_s_ctrl = empress_s_ctrl,
- .vidioc_g_chip_ident = empress_g_chip_ident,
.vidioc_s_std = empress_s_std,
.vidioc_g_std = empress_g_std,
};
@@ -488,7 +482,6 @@ static struct video_device saa7134_empress_template = {
.ioctl_ops = &ts_ioctl_ops,
.tvnorms = SAA7134_NORMS,
- .current_norm = V4L2_STD_PAL,
};
static void empress_signal_update(struct work_struct *work)
@@ -518,7 +511,7 @@ static int empress_init(struct saa7134_dev *dev)
if (NULL == dev->empress_dev)
return -ENOMEM;
*(dev->empress_dev) = saa7134_empress_template;
- dev->empress_dev->parent = &dev->pci->dev;
+ dev->empress_dev->v4l2_dev = &dev->v4l2_dev;
dev->empress_dev->release = video_device_release;
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index cc409380ee16..e12bbd8c3f0b 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -825,20 +825,22 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
return 0;
}
-static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
+static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win, bool try)
{
enum v4l2_field field;
int maxw, maxh;
- if (NULL == dev->ovbuf.base)
+ if (!try && (dev->ovbuf.base == NULL || dev->ovfmt == NULL))
return -EINVAL;
- if (NULL == dev->ovfmt)
- return -EINVAL;
- if (win->w.width < 48 || win->w.height < 32)
- return -EINVAL;
- if (win->clipcount > 2048)
- return -EINVAL;
-
+ if (win->w.width < 48)
+ win->w.width = 48;
+ if (win->w.height < 32)
+ win->w.height = 32;
+ if (win->clipcount > 8)
+ win->clipcount = 8;
+
+ win->chromakey = 0;
+ win->global_alpha = 0;
field = win->field;
maxw = dev->crop_current.width;
maxh = dev->crop_current.height;
@@ -853,10 +855,9 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
case V4L2_FIELD_BOTTOM:
maxh = maxh / 2;
break;
- case V4L2_FIELD_INTERLACED:
- break;
default:
- return -EINVAL;
+ field = V4L2_FIELD_INTERLACED;
+ break;
}
win->field = field;
@@ -872,20 +873,20 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
unsigned long base,control,bpl;
int err;
- err = verify_preview(dev,&fh->win);
+ err = verify_preview(dev, &dev->win, false);
if (0 != err)
return err;
- dev->ovfield = fh->win.field;
+ dev->ovfield = dev->win.field;
dprintk("start_preview %dx%d+%d+%d %s field=%s\n",
- fh->win.w.width,fh->win.w.height,
- fh->win.w.left,fh->win.w.top,
- dev->ovfmt->name,v4l2_field_names[dev->ovfield]);
+ dev->win.w.width, dev->win.w.height,
+ dev->win.w.left, dev->win.w.top,
+ dev->ovfmt->name, v4l2_field_names[dev->ovfield]);
/* setup window + clipping */
- set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height,
+ set_size(dev, TASK_B, dev->win.w.width, dev->win.w.height,
V4L2_FIELD_HAS_BOTH(dev->ovfield));
- setup_clipping(dev,fh->clips,fh->nclips,
+ setup_clipping(dev, dev->clips, dev->nclips,
V4L2_FIELD_HAS_BOTH(dev->ovfield));
if (dev->ovfmt->yuv)
saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);
@@ -895,8 +896,8 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
/* dma: setup channel 1 (= Video Task B) */
base = (unsigned long)dev->ovbuf.base;
- base += dev->ovbuf.fmt.bytesperline * fh->win.w.top;
- base += dev->ovfmt->depth/8 * fh->win.w.left;
+ base += dev->ovbuf.fmt.bytesperline * dev->win.w.top;
+ base += dev->ovfmt->depth/8 * dev->win.w.left;
bpl = dev->ovbuf.fmt.bytesperline;
control = SAA7134_RS_CONTROL_BURST_16;
if (dev->ovfmt->bswap)
@@ -1024,38 +1025,38 @@ static int buffer_prepare(struct videobuf_queue *q,
int err;
/* sanity checks */
- if (NULL == fh->fmt)
+ if (NULL == dev->fmt)
return -EINVAL;
- if (fh->width < 48 ||
- fh->height < 32 ||
- fh->width/4 > dev->crop_current.width ||
- fh->height/4 > dev->crop_current.height ||
- fh->width > dev->crop_bounds.width ||
- fh->height > dev->crop_bounds.height)
+ if (dev->width < 48 ||
+ dev->height < 32 ||
+ dev->width/4 > dev->crop_current.width ||
+ dev->height/4 > dev->crop_current.height ||
+ dev->width > dev->crop_bounds.width ||
+ dev->height > dev->crop_bounds.height)
return -EINVAL;
- size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+ size = (dev->width * dev->height * dev->fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
- vb->i,fh->width,fh->height,size,v4l2_field_names[field],
- fh->fmt->name);
- if (buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
+ vb->i, dev->width, dev->height, size, v4l2_field_names[field],
+ dev->fmt->name);
+ if (buf->vb.width != dev->width ||
+ buf->vb.height != dev->height ||
buf->vb.size != size ||
buf->vb.field != field ||
- buf->fmt != fh->fmt) {
+ buf->fmt != dev->fmt) {
saa7134_dma_free(q,buf);
}
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
buf->vb.size = size;
buf->vb.field = field;
- buf->fmt = fh->fmt;
+ buf->fmt = dev->fmt;
buf->pt = &fh->pt_cap;
dev->video_q.curr = NULL;
@@ -1082,8 +1083,9 @@ static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
struct saa7134_fh *fh = q->priv_data;
+ struct saa7134_dev *dev = fh->dev;
- *size = fh->fmt->depth * fh->width * fh->height >> 3;
+ *size = dev->fmt->depth * dev->width * dev->height >> 3;
if (0 == *count)
*count = gbuffers;
*count = saa7134_buffer_count(*size,*count);
@@ -1287,15 +1289,17 @@ static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
/* ------------------------------------------------------------------ */
-static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
+static struct videobuf_queue *saa7134_queue(struct file *file)
{
- struct videobuf_queue* q = NULL;
+ struct video_device *vdev = video_devdata(file);
+ struct saa7134_fh *fh = file->private_data;
+ struct videobuf_queue *q = NULL;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
q = &fh->cap;
break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case VFL_TYPE_VBI:
q = &fh->vbi;
break;
default:
@@ -1304,12 +1308,14 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
return q;
}
-static int saa7134_resource(struct saa7134_fh *fh)
+static int saa7134_resource(struct file *file)
{
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
return RESOURCE_VIDEO;
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ if (vdev->vfl_type == VFL_TYPE_VBI)
return RESOURCE_VBI;
BUG();
@@ -1321,23 +1327,6 @@ static int video_open(struct file *file)
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh;
- enum v4l2_buf_type type = 0;
- int radio = 0;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev),
- radio, v4l2_type_names[type]);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1347,11 +1336,6 @@ static int video_open(struct file *file)
v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
fh->dev = dev;
- fh->radio = radio;
- fh->type = type;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- fh->width = 720;
- fh->height = 576;
videobuf_queue_sg_init(&fh->cap, &video_qops,
&dev->pci->dev, &dev->slock,
@@ -1368,7 +1352,7 @@ static int video_open(struct file *file)
saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
- if (fh->radio) {
+ if (vdev->vfl_type == VFL_TYPE_RADIO) {
/* switch to radio mode */
saa7134_tvaudio_setinput(dev,&card(dev).radio);
saa_call_all(dev, tuner, s_radio);
@@ -1384,19 +1368,20 @@ static int video_open(struct file *file)
static ssize_t
video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7134_fh *fh = file->private_data;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
if (res_locked(fh->dev,RESOURCE_VIDEO))
return -EBUSY;
- return videobuf_read_one(saa7134_queue(fh),
+ return videobuf_read_one(saa7134_queue(file),
data, count, ppos,
file->f_flags & O_NONBLOCK);
- case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case VFL_TYPE_VBI:
if (!res_get(fh->dev,fh,RESOURCE_VBI))
return -EBUSY;
- return videobuf_read_stream(saa7134_queue(fh),
+ return videobuf_read_stream(saa7134_queue(file),
data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
break;
@@ -1409,11 +1394,12 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
static unsigned int
video_poll(struct file *file, struct poll_table_struct *wait)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7134_fh *fh = file->private_data;
struct videobuf_buffer *buf = NULL;
unsigned int rc = 0;
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
+ if (vdev->vfl_type == VFL_TYPE_VBI)
return videobuf_poll_stream(file, &fh->vbi, wait);
if (res_check(fh,RESOURCE_VIDEO)) {
@@ -1451,6 +1437,7 @@ err:
static int video_release(struct file *file)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
struct saa6588_command cmd;
@@ -1489,7 +1476,7 @@ static int video_release(struct file *file)
saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
saa_call_all(dev, core, s_power, 0);
- if (fh->radio)
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
/* free stuff */
@@ -1507,9 +1494,7 @@ static int video_release(struct file *file)
static int video_mmap(struct file *file, struct vm_area_struct * vma)
{
- struct saa7134_fh *fh = file->private_data;
-
- return videobuf_mmap_mapper(saa7134_queue(fh), vma);
+ return videobuf_mmap_mapper(saa7134_queue(file), vma);
}
static ssize_t radio_read(struct file *file, char __user *data,
@@ -1570,15 +1555,18 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
+ struct saa7134_dev *dev = fh->dev;
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
f->fmt.pix.field = fh->cap.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ (f->fmt.pix.width * dev->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1586,14 +1574,33 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
+ struct saa7134_dev *dev = fh->dev;
+ struct v4l2_clip __user *clips = f->fmt.win.clips;
+ u32 clipcount = f->fmt.win.clipcount;
+ int err = 0;
+ int i;
if (saa7134_no_overlay > 0) {
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
return -EINVAL;
}
- f->fmt.win = fh->win;
+ mutex_lock(&dev->lock);
+ f->fmt.win = dev->win;
+ f->fmt.win.clips = clips;
+ if (clips == NULL)
+ clipcount = 0;
+ if (dev->nclips < clipcount)
+ clipcount = dev->nclips;
+ f->fmt.win.clipcount = clipcount;
+
+ for (i = 0; !err && i < clipcount; i++) {
+ if (copy_to_user(&f->fmt.win.clips[i].c, &dev->clips[i].c,
+ sizeof(struct v4l2_rect)))
+ err = -EFAULT;
+ }
+ mutex_unlock(&dev->lock);
- return 0;
+ return err;
}
static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
@@ -1623,10 +1630,9 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
case V4L2_FIELD_BOTTOM:
maxh = maxh / 2;
break;
- case V4L2_FIELD_INTERLACED:
- break;
default:
- return -EINVAL;
+ field = V4L2_FIELD_INTERLACED;
+ break;
}
f->fmt.pix.field = field;
@@ -1643,6 +1649,8 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1658,22 +1666,25 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
return -EINVAL;
}
- return verify_preview(dev, &f->fmt.win);
+ if (f->fmt.win.clips == NULL)
+ f->fmt.win.clipcount = 0;
+ return verify_preview(dev, &f->fmt.win, true);
}
static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
+ struct saa7134_dev *dev = fh->dev;
int err;
err = saa7134_try_fmt_vid_cap(file, priv, f);
if (0 != err)
return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
fh->cap.field = f->fmt.pix.field;
return 0;
}
@@ -1690,20 +1701,19 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
return -EINVAL;
}
- err = verify_preview(dev, &f->fmt.win);
+ if (f->fmt.win.clips == NULL)
+ f->fmt.win.clipcount = 0;
+ err = verify_preview(dev, &f->fmt.win, true);
if (0 != err)
return err;
mutex_lock(&dev->lock);
- fh->win = f->fmt.win;
- fh->nclips = f->fmt.win.clipcount;
+ dev->win = f->fmt.win;
+ dev->nclips = f->fmt.win.clipcount;
- if (fh->nclips > 8)
- fh->nclips = 8;
-
- if (copy_from_user(fh->clips, f->fmt.win.clips,
- sizeof(struct v4l2_clip)*fh->nclips)) {
+ if (copy_from_user(dev->clips, f->fmt.win.clips,
+ sizeof(struct v4l2_clip) * dev->nclips)) {
mutex_unlock(&dev->lock);
return -EFAULT;
}
@@ -2057,7 +2067,6 @@ static int saa7134_g_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
saa_call_all(dev, tuner, g_frequency, f);
return 0;
@@ -2071,10 +2080,6 @@ static int saa7134_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
- return -EINVAL;
- if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
- return -EINVAL;
mutex_lock(&dev->lock);
saa_call_all(dev, tuner, s_frequency, f);
@@ -2186,27 +2191,23 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on)
static int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
- struct saa7134_fh *fh = priv;
- return videobuf_reqbufs(saa7134_queue(fh), p);
+ return videobuf_reqbufs(saa7134_queue(file), p);
}
static int saa7134_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- return videobuf_querybuf(saa7134_queue(fh), b);
+ return videobuf_querybuf(saa7134_queue(file), b);
}
static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- return videobuf_qbuf(saa7134_queue(fh), b);
+ return videobuf_qbuf(saa7134_queue(file), b);
}
static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- return videobuf_dqbuf(saa7134_queue(fh), b,
+ return videobuf_dqbuf(saa7134_queue(file), b,
file->f_flags & O_NONBLOCK);
}
@@ -2215,7 +2216,7 @@ static int saa7134_streamon(struct file *file, void *priv,
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- int res = saa7134_resource(fh);
+ int res = saa7134_resource(file);
if (!res_get(dev, fh, res))
return -EBUSY;
@@ -2227,11 +2228,11 @@ static int saa7134_streamon(struct file *file, void *priv,
* Unfortunately, I lack register-level documentation to check the
* Linux FIFO setup and confirm the perfect value.
*/
- pm_qos_add_request(&fh->qos_request,
+ pm_qos_add_request(&dev->qos_request,
PM_QOS_CPU_DMA_LATENCY,
20);
- return videobuf_streamon(saa7134_queue(fh));
+ return videobuf_streamon(saa7134_queue(file));
}
static int saa7134_streamoff(struct file *file, void *priv,
@@ -2240,11 +2241,11 @@ static int saa7134_streamoff(struct file *file, void *priv,
int err;
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- int res = saa7134_resource(fh);
+ int res = saa7134_resource(file);
- pm_qos_remove_request(&fh->qos_request);
+ pm_qos_remove_request(&dev->qos_request);
- err = videobuf_streamoff(saa7134_queue(fh));
+ err = videobuf_streamoff(saa7134_queue(file));
if (err < 0)
return err;
res_free(dev, fh, res);
@@ -2258,9 +2259,7 @@ static int vidioc_g_register (struct file *file, void *priv,
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- reg->val = saa_readb(reg->reg);
+ reg->val = saa_readb(reg->reg & 0xffffff);
reg->size = 1;
return 0;
}
@@ -2271,9 +2270,7 @@ static int vidioc_s_register (struct file *file, void *priv,
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- saa_writeb(reg->reg&0xffffff, reg->val);
+ saa_writeb(reg->reg & 0xffffff, reg->val);
return 0;
}
#endif
@@ -2287,9 +2284,7 @@ static int radio_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- memset(t, 0, sizeof(*t));
strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
saa_call_all(dev, tuner, g_tuner, t);
t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
@@ -2443,7 +2438,6 @@ struct video_device saa7134_video_template = {
.fops = &video_fops,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = SAA7134_NORMS,
- .current_norm = V4L2_STD_PAL,
};
struct video_device saa7134_radio_template = {
@@ -2480,6 +2474,16 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->video_q.timeout.function = saa7134_buffer_timeout;
dev->video_q.timeout.data = (unsigned long)(&dev->video_q);
dev->video_q.dev = dev;
+ dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ dev->width = 720;
+ dev->height = 576;
+ dev->win.w.width = dev->width;
+ dev->win.w.height = dev->height;
+ dev->win.field = V4L2_FIELD_INTERLACED;
+ dev->ovbuf.fmt.width = dev->width;
+ dev->ovbuf.fmt.height = dev->height;
+ dev->ovbuf.fmt.pixelformat = dev->fmt->fourcc;
+ dev->ovbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
if (saa7134_boards[dev->board].video_out)
saa7134_videoport_init(dev);
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index d2ad16c1569a..8d1453a48014 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -471,19 +471,9 @@ struct saa7134_dmaqueue {
struct saa7134_fh {
struct v4l2_fh fh;
struct saa7134_dev *dev;
- unsigned int radio;
- enum v4l2_buf_type type;
unsigned int resources;
- struct pm_qos_request qos_request;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip clips[8];
- unsigned int nclips;
/* video capture */
- struct saa7134_format *fmt;
- unsigned int width,height;
struct videobuf_queue cap;
struct saa7134_pgtable pt_cap;
@@ -592,12 +582,19 @@ struct saa7134_dev {
struct saa7134_format *ovfmt;
unsigned int ovenable;
enum v4l2_field ovfield;
+ struct v4l2_window win;
+ struct v4l2_clip clips[8];
+ unsigned int nclips;
+
/* video+ts+vbi capture */
struct saa7134_dmaqueue video_q;
struct saa7134_dmaqueue vbi_q;
unsigned int video_fieldcount;
unsigned int vbi_fieldcount;
+ struct saa7134_format *fmt;
+ unsigned int width, height;
+ struct pm_qos_request qos_request;
/* various v4l controls */
struct saa7134_tvnorm *tvnorm; /* video */
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 71e8bead321b..33abe332d175 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -669,14 +669,10 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (v4l2_chip_match_host(&reg->match)) {
- reg->val = saa7146_read(dev, reg->reg);
- reg->size = 4;
- return 0;
- }
- call_all(dev, core, g_register, reg);
+ if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
+ return -EINVAL;
+ reg->val = saa7146_read(dev, reg->reg);
+ reg->size = 4;
return 0;
}
@@ -684,13 +680,10 @@ static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (v4l2_chip_match_host(&reg->match)) {
- saa7146_write(dev, reg->reg, reg->val);
- return 0;
- }
- return call_all(dev, core, s_register, reg);
+ if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
+ return -EINVAL;
+ saa7146_write(dev, reg->reg, reg->val);
+ return 0;
}
#endif
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 7618fdae811e..d37ee37aaefe 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1196,6 +1196,12 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
if (NULL == dev)
return -ENOMEM;
+ err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+ if (err < 0) {
+ dev_err(&pci_dev->dev, "v4l2_device_register failed\n");
+ goto fail_free;
+ }
+
/* pci init */
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
@@ -1367,6 +1373,7 @@ fail_fw:
fail_irq:
saa7164_dev_unregister(dev);
fail_free:
+ v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
return err;
}
@@ -1439,6 +1446,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev)
mutex_unlock(&devlist);
saa7164_dev_unregister(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
}
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index 0b74fb2300dd..9266965412c3 100644
--- a/drivers/media/pci/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -228,6 +228,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
return -EINVAL;
port->encodernorm = saa7164_tvnorms[i];
+ port->std = id;
/* Update the audio decoder while is not running in
* auto detect mode.
@@ -239,6 +240,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+
+ *id = port->std;
+ return 0;
+}
+
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
@@ -1288,46 +1298,9 @@ static const struct v4l2_file_operations mpeg_fops = {
.unlocked_ioctl = video_ioctl2,
};
-static int saa7164_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
- struct saa7164_dev *dev = port->dev;
- dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int saa7164_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
- struct saa7164_dev *dev = port->dev;
- dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- return 0;
-}
-
-static int saa7164_s_register(struct file *file, void *fh,
- const struct v4l2_dbg_register *reg)
-{
- struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
- struct saa7164_dev *dev = port->dev;
- dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- return 0;
-}
-#endif
-
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1346,11 +1319,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_chip_ident = saa7164_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = saa7164_g_register,
- .vidioc_s_register = saa7164_s_register,
-#endif
};
static struct video_device saa7164_mpeg_template = {
@@ -1359,7 +1327,6 @@ static struct video_device saa7164_mpeg_template = {
.ioctl_ops = &mpeg_ioctl_ops,
.minor = -1,
.tvnorms = SAA7164_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
};
static struct video_device *saa7164_encoder_alloc(
@@ -1381,7 +1348,7 @@ static struct video_device *saa7164_encoder_alloc(
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, saa7164_boards[dev->board].name);
- vfd->parent = &pci->dev;
+ vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
return vfd;
}
@@ -1426,6 +1393,7 @@ int saa7164_encoder_register(struct saa7164_port *port)
port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
port->encoder_params.refdist = 1;
port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
+ port->std = V4L2_STD_NTSC_M;
if (port->encodernorm.id & V4L2_STD_525_60)
port->height = 480;
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index da224eb39b95..6e025fea2542 100644
--- a/drivers/media/pci/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -200,6 +200,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
return -EINVAL;
port->encodernorm = saa7164_tvnorms[i];
+ port->std = id;
/* Update the audio decoder while is not running in
* auto detect mode.
@@ -211,6 +212,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+
+ *id = port->std;
+ return 0;
+}
+
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
@@ -1236,6 +1246,7 @@ static const struct v4l2_file_operations vbi_fops = {
static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1254,15 +1265,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_queryctrl = vidioc_queryctrl,
-#if 0
- .vidioc_g_chip_ident = saa7164_g_chip_ident,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-#if 0
- .vidioc_g_register = saa7164_g_register,
- .vidioc_s_register = saa7164_s_register,
-#endif
-#endif
.vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt,
.vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt,
.vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt,
@@ -1274,7 +1276,6 @@ static struct video_device saa7164_vbi_template = {
.ioctl_ops = &vbi_ioctl_ops,
.minor = -1,
.tvnorms = SAA7164_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
};
static struct video_device *saa7164_vbi_alloc(
@@ -1296,7 +1297,7 @@ static struct video_device *saa7164_vbi_alloc(
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, saa7164_boards[dev->board].name);
- vfd->parent = &pci->dev;
+ vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
return vfd;
}
@@ -1333,6 +1334,7 @@ int saa7164_vbi_register(struct saa7164_port *port)
goto failed;
}
+ port->std = V4L2_STD_NTSC_M;
video_set_drvdata(port->v4l_device, port);
result = video_register_device(port->v4l_device,
VFL_TYPE_VBI, -1);
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
index 437284e747c9..8b29e8990301 100644
--- a/drivers/media/pci/saa7164/saa7164.h
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -63,7 +63,7 @@
#include <dmxdev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
#include "saa7164-reg.h"
#include "saa7164-types.h"
@@ -376,6 +376,7 @@ struct saa7164_port {
/* Encoder */
/* Defaults established in saa7164-encoder.c */
struct saa7164_tvnorm encodernorm;
+ v4l2_std_id std;
u32 height;
u32 width;
u32 freq;
@@ -427,6 +428,8 @@ struct saa7164_dev {
struct list_head devlist;
atomic_t refcount;
+ struct v4l2_device v4l2_dev;
+
/* pci stuff */
struct pci_dev *pci;
unsigned char pci_rev, pci_lat;
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 7005695aa4bd..77edc113e485 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -1047,7 +1047,8 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
ret = sta2x11_vip_init_controls(vip);
if (ret)
goto free_mem;
- if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
+ ret = v4l2_device_register(&pdev->dev, &vip->v4l2_dev);
+ if (ret)
goto free_mem;
dev_dbg(&pdev->dev, "BAR #0 at 0x%lx 0x%lx irq %d\n",
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 1f8b1bb0bf9f..0ba3875af22e 100644
--- a/drivers/media/pci/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -1128,7 +1128,7 @@ static struct stb0899_config knc1_dvbs2_config = {
// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */
.xtal_freq = 27000000,
- .inversion = IQ_SWAP_OFF, /* 1 */
+ .inversion = IQ_SWAP_OFF,
.lo_clk = 76500000,
.hi_clk = 90000000,
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 98e524178765..0acf9202103d 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -1280,7 +1280,7 @@ static struct stb0899_config tt3200_config = {
.demod_address = 0x68,
.xtal_freq = 27000000,
- .inversion = IQ_SWAP_ON, /* 1 */
+ .inversion = IQ_SWAP_ON,
.lo_clk = 76500000,
.hi_clk = 99000000,
diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
index bb53d2488ad0..923d59a321f8 100644
--- a/drivers/media/pci/zoran/zoran_card.c
+++ b/drivers/media/pci/zoran/zoran_card.c
@@ -1050,7 +1050,7 @@ static int zr36057_init (struct zoran *zr)
* Now add the template and register the device unit.
*/
memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
- zr->video_dev->parent = &zr->pci_dev->dev;
+ zr->video_dev->v4l2_dev = &zr->v4l2_dev;
strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
/* It's not a mem2mem device, but you can both capture and output from
one and the same device. This should really be split up into two
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index d133c30c3fdc..e7e9840c6c35 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -1456,29 +1456,6 @@ zoran_set_norm (struct zoran *zr,
return -EINVAL;
}
- if (norm == V4L2_STD_ALL) {
- unsigned int status = 0;
- v4l2_std_id std = 0;
-
- decoder_call(zr, video, querystd, &std);
- decoder_call(zr, core, s_std, std);
-
- /* let changes come into effect */
- ssleep(2);
-
- decoder_call(zr, video, g_input_status, &status);
- if (status & V4L2_IN_ST_NO_SIGNAL) {
- dprintk(1,
- KERN_ERR
- "%s: %s - no norm detected\n",
- ZR_DEVNAME(zr), __func__);
- /* reset norm */
- decoder_call(zr, core, s_std, zr->norm);
- return -EIO;
- }
-
- norm = std;
- }
if (norm & V4L2_STD_SECAM)
zr->timing = zr->card.tvn[2];
else if (norm & V4L2_STD_NTSC)
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 25eaf61b98b4..08de865cc399 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -36,7 +36,7 @@ source "drivers/media/platform/blackfin/Kconfig"
config VIDEO_SH_VOU
tristate "SuperH VOU video output driver"
depends on MEDIA_CAMERA_SUPPORT
- depends on VIDEO_DEV && ARCH_SHMOBILE
+ depends on VIDEO_DEV && ARCH_SHMOBILE && I2C
select VIDEOBUF_DMA_CONTIG
help
Support for the Video Output Unit (VOU) on SuperH SoCs.
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 0e55b087076f..7f838c681cea 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -32,7 +32,6 @@
#include <linux/time.h>
#include <linux/types.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -649,18 +648,30 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std)
return 0;
}
-static int bcap_g_dv_timings(struct file *file, void *priv,
+static int bcap_enum_dv_timings(struct file *file, void *priv,
+ struct v4l2_enum_dv_timings *timings)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return v4l2_subdev_call(bcap_dev->sd, video,
+ enum_dv_timings, timings);
+}
+
+static int bcap_query_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
struct bcap_device *bcap_dev = video_drvdata(file);
- int ret;
- ret = v4l2_subdev_call(bcap_dev->sd, video,
- g_dv_timings, timings);
- if (ret < 0)
- return ret;
+ return v4l2_subdev_call(bcap_dev->sd, video,
+ query_dv_timings, timings);
+}
- bcap_dev->dv_timings = *timings;
+static int bcap_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ *timings = bcap_dev->dv_timings;
return 0;
}
@@ -864,41 +875,6 @@ static int bcap_s_parm(struct file *file, void *fh,
return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
}
-static int bcap_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
-
- 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)
- return -EINVAL;
-
- return v4l2_subdev_call(bcap_dev->sd, core,
- g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int bcap_dbg_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
-
- return v4l2_subdev_call(bcap_dev->sd, core,
- g_register, reg);
-}
-
-static int bcap_dbg_s_register(struct file *file, void *priv,
- const struct v4l2_dbg_register *reg)
-{
- struct bcap_device *bcap_dev = video_drvdata(file);
-
- return v4l2_subdev_call(bcap_dev->sd, core,
- s_register, reg);
-}
-#endif
-
static int bcap_log_status(struct file *file, void *priv)
{
struct bcap_device *bcap_dev = video_drvdata(file);
@@ -921,6 +897,8 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
.vidioc_g_std = bcap_g_std,
.vidioc_s_dv_timings = bcap_s_dv_timings,
.vidioc_g_dv_timings = bcap_g_dv_timings,
+ .vidioc_query_dv_timings = bcap_query_dv_timings,
+ .vidioc_enum_dv_timings = bcap_enum_dv_timings,
.vidioc_reqbufs = bcap_reqbufs,
.vidioc_querybuf = bcap_querybuf,
.vidioc_qbuf = bcap_qbuf,
@@ -929,11 +907,6 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
.vidioc_streamoff = bcap_streamoff,
.vidioc_g_parm = bcap_g_parm,
.vidioc_s_parm = bcap_s_parm,
- .vidioc_g_chip_ident = bcap_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = bcap_dbg_g_register,
- .vidioc_s_register = bcap_dbg_s_register,
-#endif
.vidioc_log_status = bcap_log_status,
};
@@ -960,7 +933,7 @@ static int bcap_probe(struct platform_device *pdev)
int ret;
config = pdev->dev.platform_data;
- if (!config) {
+ if (!config || !config->num_inputs) {
v4l2_err(pdev->dev.driver, "Unable to get board config\n");
return -ENODEV;
}
@@ -1031,7 +1004,9 @@ static int bcap_probe(struct platform_device *pdev)
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vb2_queue_init(q);
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto err_free_handler;
mutex_init(&bcap_dev->mutex);
init_completion(&bcap_dev->comp);
@@ -1067,11 +1042,6 @@ static int bcap_probe(struct platform_device *pdev)
NULL);
if (bcap_dev->sd) {
int i;
- if (!config->num_inputs) {
- v4l2_err(&bcap_dev->v4l2_dev,
- "Unable to work without input\n");
- goto err_unreg_vdev;
- }
/* update tvnorms from the sub devices */
for (i = 0; i < config->num_inputs; i++)
@@ -1079,6 +1049,7 @@ static int bcap_probe(struct platform_device *pdev)
} else {
v4l2_err(&bcap_dev->v4l2_dev,
"Unable to register sub device\n");
+ ret = -ENODEV;
goto err_unreg_vdev;
}
diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c
index 01b5b501347e..15e9c2bac2b1 100644
--- a/drivers/media/platform/blackfin/ppi.c
+++ b/drivers/media/platform/blackfin/ppi.c
@@ -266,6 +266,18 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
bfin_write32(&reg->vcnt, params->height);
if (params->int_mask)
bfin_write32(&reg->imsk, params->int_mask & 0xFF);
+ if (ppi->ppi_control & PORT_DIR) {
+ u32 hsync_width, vsync_width, vsync_period;
+
+ hsync_width = params->hsync
+ * params->bpp / params->dlen;
+ vsync_width = params->vsync * samples_per_line;
+ vsync_period = samples_per_line * params->frame;
+ bfin_write32(&reg->fs1_wlhb, hsync_width);
+ bfin_write32(&reg->fs1_paspl, samples_per_line);
+ bfin_write32(&reg->fs2_wlvb, vsync_width);
+ bfin_write32(&reg->fs2_palpf, vsync_period);
+ }
break;
}
default:
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 9d1481a60bd9..df4ada880e42 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -49,16 +49,14 @@
#define CODA_MAX_FRAMEBUFFERS 2
-#define MAX_W 720
-#define MAX_H 576
-#define CODA_MAX_FRAME_SIZE 0x90000
+#define MAX_W 8192
+#define MAX_H 8192
+#define CODA_MAX_FRAME_SIZE 0x100000
#define FMO_SLICE_SAVE_BUF_SIZE (32)
#define CODA_DEFAULT_GAMMA 4096
#define MIN_W 176
#define MIN_H 144
-#define MAX_W 720
-#define MAX_H 576
#define S_ALIGN 1 /* multiple of 2 */
#define W_ALIGN 1 /* multiple of 2 */
@@ -67,7 +65,7 @@
#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh)
static int coda_debug;
-module_param(coda_debug, int, 0);
+module_param(coda_debug, int, 0644);
MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
enum {
@@ -75,11 +73,6 @@ enum {
V4L2_M2M_DST = 1,
};
-enum coda_fmt_type {
- CODA_FMT_ENC,
- CODA_FMT_RAW,
-};
-
enum coda_inst_type {
CODA_INST_ENCODER,
CODA_INST_DECODER,
@@ -93,14 +86,21 @@ enum coda_product {
struct coda_fmt {
char *name;
u32 fourcc;
- enum coda_fmt_type type;
+};
+
+struct coda_codec {
+ u32 mode;
+ u32 src_fourcc;
+ u32 dst_fourcc;
+ u32 max_w;
+ u32 max_h;
};
struct coda_devtype {
char *firmware;
enum coda_product product;
- struct coda_fmt *formats;
- unsigned int num_formats;
+ struct coda_codec *codecs;
+ unsigned int num_codecs;
size_t workbuf_size;
};
@@ -109,7 +109,7 @@ struct coda_q_data {
unsigned int width;
unsigned int height;
unsigned int sizeimage;
- struct coda_fmt *fmt;
+ unsigned int fourcc;
};
struct coda_aux_buf {
@@ -137,12 +137,12 @@ struct coda_dev {
spinlock_t irqlock;
struct mutex dev_mutex;
+ struct mutex coda_mutex;
struct v4l2_m2m_dev *m2m_dev;
struct vb2_alloc_ctx *alloc_ctx;
struct list_head instances;
unsigned long instance_mask;
struct delayed_work timeout;
- struct completion done;
};
struct coda_params {
@@ -164,11 +164,12 @@ struct coda_ctx {
struct coda_dev *dev;
struct list_head list;
int aborting;
- int rawstreamon;
- int compstreamon;
+ int streamon_out;
+ int streamon_cap;
u32 isequence;
struct coda_q_data q_data[2];
enum coda_inst_type inst_type;
+ struct coda_codec *codec;
enum v4l2_colorspace colorspace;
struct coda_params params;
struct v4l2_m2m_ctx *m2m_ctx;
@@ -257,62 +258,89 @@ static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
}
/*
- * Add one array of supported formats for each version of Coda:
- * i.MX27 -> codadx6
- * i.MX51 -> coda7
- * i.MX6 -> coda960
+ * Array of all formats supported by any version of Coda:
*/
-static struct coda_fmt codadx6_formats[] = {
+static struct coda_fmt coda_formats[] = {
{
- .name = "YUV 4:2:0 Planar",
+ .name = "YUV 4:2:0 Planar, YCbCr",
.fourcc = V4L2_PIX_FMT_YUV420,
- .type = CODA_FMT_RAW,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .type = CODA_FMT_ENC,
},
{
- .name = "MPEG4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .type = CODA_FMT_ENC,
- },
-};
-
-static struct coda_fmt coda7_formats[] = {
- {
- .name = "YUV 4:2:0 Planar",
- .fourcc = V4L2_PIX_FMT_YUV420,
- .type = CODA_FMT_RAW,
+ .name = "YUV 4:2:0 Planar, YCrCb",
+ .fourcc = V4L2_PIX_FMT_YVU420,
},
{
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
- .type = CODA_FMT_ENC,
},
{
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
- .type = CODA_FMT_ENC,
},
};
-static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f)
+#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
+ { mode, src_fourcc, dst_fourcc, max_w, max_h }
+
+/*
+ * Arrays of codecs supported by each given version of Coda:
+ * i.MX27 -> codadx6
+ * i.MX5x -> coda7
+ * i.MX6 -> coda960
+ * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
+ */
+static struct coda_codec codadx6_codecs[] = {
+ CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576),
+ CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
+};
+
+static struct coda_codec coda7_codecs[] = {
+ CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720),
+ CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
+};
+
+static bool coda_format_is_yuv(u32 fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Normalize all supported YUV 4:2:0 formats to the value used in the codec
+ * tables.
+ */
+static u32 coda_format_normalize_yuv(u32 fourcc)
+{
+ return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
+}
+
+static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
+ int dst_fourcc)
{
- struct coda_fmt *formats = dev->devtype->formats;
- int num_formats = dev->devtype->num_formats;
- unsigned int k;
+ struct coda_codec *codecs = dev->devtype->codecs;
+ int num_codecs = dev->devtype->num_codecs;
+ int k;
+
+ src_fourcc = coda_format_normalize_yuv(src_fourcc);
+ dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
+ if (src_fourcc == dst_fourcc)
+ return NULL;
- for (k = 0; k < num_formats; k++) {
- if (formats[k].fourcc == f->fmt.pix.pixelformat)
+ for (k = 0; k < num_codecs; k++) {
+ if (codecs[k].src_fourcc == src_fourcc &&
+ codecs[k].dst_fourcc == dst_fourcc)
break;
}
- if (k == num_formats)
+ if (k == num_codecs)
return NULL;
- return &formats[k];
+ return &codecs[k];
}
/*
@@ -323,7 +351,7 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
- strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info));
+ strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
@@ -337,17 +365,34 @@ static int vidioc_querycap(struct file *file, void *priv,
}
static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
- enum coda_fmt_type type)
+ enum v4l2_buf_type type)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- struct coda_dev *dev = ctx->dev;
- struct coda_fmt *formats = dev->devtype->formats;
+ struct coda_codec *codecs = ctx->dev->devtype->codecs;
+ struct coda_fmt *formats = coda_formats;
struct coda_fmt *fmt;
- int num_formats = dev->devtype->num_formats;
- int i, num = 0;
+ int num_codecs = ctx->dev->devtype->num_codecs;
+ int num_formats = ARRAY_SIZE(coda_formats);
+ int i, k, num = 0;
for (i = 0; i < num_formats; i++) {
- if (formats[i].type == type) {
+ /* Both uncompressed formats are always supported */
+ if (coda_format_is_yuv(formats[i].fourcc)) {
+ if (num == f->index)
+ break;
+ ++num;
+ continue;
+ }
+ /* Compressed formats may be supported, check the codec list */
+ for (k = 0; k < num_codecs; k++) {
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ formats[i].fourcc == codecs[k].dst_fourcc)
+ break;
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ formats[i].fourcc == codecs[k].src_fourcc)
+ break;
+ }
+ if (k < num_codecs) {
if (num == f->index)
break;
++num;
@@ -368,13 +413,13 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return enum_fmt(priv, f, CODA_FMT_ENC);
+ return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE);
}
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return enum_fmt(priv, f, CODA_FMT_RAW);
+ return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT);
}
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -390,10 +435,10 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
q_data = get_q_data(ctx, f->type);
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+ f->fmt.pix.pixelformat = q_data->fourcc;
f->fmt.pix.width = q_data->width;
f->fmt.pix.height = q_data->height;
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ if (coda_format_is_yuv(f->fmt.pix.pixelformat))
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
else /* encoded formats h.264/mpeg4 */
f->fmt.pix.bytesperline = 0;
@@ -404,8 +449,9 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
return 0;
}
-static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
+static int vidioc_try_fmt(struct coda_codec *codec, struct v4l2_format *f)
{
+ unsigned int max_w, max_h;
enum v4l2_field field;
field = f->fmt.pix.field;
@@ -418,12 +464,21 @@ static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
* if any of the dimensions is unsupported */
f->fmt.pix.field = field;
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
- v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
- W_ALIGN, &f->fmt.pix.height,
- MIN_H, MAX_H, H_ALIGN, S_ALIGN);
- f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
- f->fmt.pix.sizeimage = f->fmt.pix.width *
+ if (codec) {
+ max_w = codec->max_w;
+ max_h = codec->max_h;
+ } else {
+ max_w = MAX_W;
+ max_h = MAX_H;
+ }
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w,
+ W_ALIGN, &f->fmt.pix.height,
+ MIN_H, max_h, H_ALIGN, S_ALIGN);
+
+ if (coda_format_is_yuv(f->fmt.pix.pixelformat)) {
+ /* Frame stride must be multiple of 8 */
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
} else { /*encoded formats h.264/mpeg4 */
f->fmt.pix.bytesperline = 0;
@@ -436,57 +491,38 @@ static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- int ret;
- struct coda_fmt *fmt;
struct coda_ctx *ctx = fh_to_ctx(priv);
+ struct coda_codec *codec = NULL;
- fmt = find_format(ctx->dev, f);
- /*
- * Since decoding support is not implemented yet do not allow
- * CODA_FMT_RAW formats in the capture interface.
- */
- if (!fmt || !(fmt->type == CODA_FMT_ENC))
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+ /* Determine codec by the encoded format */
+ codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+ f->fmt.pix.pixelformat);
f->fmt.pix.colorspace = ctx->colorspace;
- ret = vidioc_try_fmt(ctx->dev, f);
- if (ret < 0)
- return ret;
-
- return 0;
+ return vidioc_try_fmt(codec, f);
}
static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- struct coda_fmt *fmt;
- int ret;
+ struct coda_codec *codec;
- fmt = find_format(ctx->dev, f);
- /*
- * Since decoding support is not implemented yet do not allow
- * CODA_FMT formats in the capture interface.
- */
- if (!fmt || !(fmt->type == CODA_FMT_RAW))
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+ /* Determine codec by encoded format, returns NULL if raw or invalid */
+ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+ V4L2_PIX_FMT_YUV420);
if (!f->fmt.pix.colorspace)
f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
- ret = vidioc_try_fmt(ctx->dev, f);
- if (ret < 0)
- return ret;
-
- return 0;
+ return vidioc_try_fmt(codec, f);
}
static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
{
struct coda_q_data *q_data;
struct vb2_queue *vq;
- int ret;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
if (!vq)
@@ -501,18 +537,14 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
return -EBUSY;
}
- ret = vidioc_try_fmt(ctx->dev, f);
- if (ret)
- return ret;
-
- q_data->fmt = find_format(ctx->dev, f);
+ q_data->fourcc = f->fmt.pix.pixelformat;
q_data->width = f->fmt.pix.width;
q_data->height = f->fmt.pix.height;
q_data->sizeimage = f->fmt.pix.sizeimage;
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
- f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+ f->type, q_data->width, q_data->height, q_data->fourcc);
return 0;
}
@@ -520,13 +552,14 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
- return vidioc_s_fmt(fh_to_ctx(priv), f);
+ return vidioc_s_fmt(ctx, f);
}
static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
@@ -569,6 +602,14 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
+static int vidioc_expbuf(struct file *file, void *priv,
+ struct v4l2_exportbuffer *eb)
+{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+}
+
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
@@ -617,6 +658,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
+ .vidioc_expbuf = vidioc_expbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_create_bufs = vidioc_create_bufs,
@@ -639,11 +681,13 @@ static void coda_device_run(void *m2m_priv)
u32 pic_stream_buffer_addr, pic_stream_buffer_size;
u32 dst_fourcc;
+ mutex_lock(&dev->coda_mutex);
+
src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- dst_fourcc = q_data_dst->fmt->fourcc;
+ dst_fourcc = q_data_dst->fourcc;
src_buf->v4l2_buf.sequence = ctx->isequence;
dst_buf->v4l2_buf.sequence = ctx->isequence;
@@ -725,9 +769,20 @@ static void coda_device_run(void *m2m_priv)
picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- picture_cb = picture_y + q_data_src->width * q_data_src->height;
- picture_cr = picture_cb + q_data_src->width / 2 *
- q_data_src->height / 2;
+ switch (q_data_src->fourcc) {
+ case V4L2_PIX_FMT_YVU420:
+ /* Switch Cb and Cr for YVU420 format */
+ picture_cr = picture_y + q_data_src->width * q_data_src->height;
+ picture_cb = picture_cr + q_data_src->width / 2 *
+ q_data_src->height / 2;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ default:
+ picture_cb = picture_y + q_data_src->width * q_data_src->height;
+ picture_cr = picture_cb + q_data_src->width / 2 *
+ q_data_src->height / 2;
+ break;
+ }
coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
@@ -748,7 +803,6 @@ static void coda_device_run(void *m2m_priv)
/* 1 second timeout in case CODA locks up */
schedule_delayed_work(&dev->timeout, HZ);
- INIT_COMPLETION(dev->done);
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
}
@@ -767,6 +821,12 @@ static int coda_job_ready(void *m2m_priv)
return 0;
}
+ if (ctx->aborting) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "not ready: aborting\n");
+ return 0;
+ }
+
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"job ready\n");
return 1;
@@ -775,14 +835,11 @@ static int coda_job_ready(void *m2m_priv)
static void coda_job_abort(void *priv)
{
struct coda_ctx *ctx = priv;
- struct coda_dev *dev = ctx->dev;
ctx->aborting = 1;
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Aborting task\n");
-
- v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
}
static void coda_lock(void *m2m_priv)
@@ -809,7 +866,12 @@ static struct v4l2_m2m_ops coda_m2m_ops = {
static void set_default_params(struct coda_ctx *ctx)
{
- struct coda_dev *dev = ctx->dev;
+ int max_w;
+ int max_h;
+
+ ctx->codec = &ctx->dev->devtype->codecs[0];
+ max_w = ctx->codec->max_w;
+ max_h = ctx->codec->max_h;
ctx->params.codec_mode = CODA_MODE_INVALID;
ctx->colorspace = V4L2_COLORSPACE_REC709;
@@ -817,13 +879,13 @@ static void set_default_params(struct coda_ctx *ctx)
ctx->aborting = 0;
/* Default formats for output and input queues */
- ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0];
- ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1];
- ctx->q_data[V4L2_M2M_SRC].width = MAX_W;
- ctx->q_data[V4L2_M2M_SRC].height = MAX_H;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2;
- ctx->q_data[V4L2_M2M_DST].width = MAX_W;
- ctx->q_data[V4L2_M2M_DST].height = MAX_H;
+ ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
+ ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
+ ctx->q_data[V4L2_M2M_SRC].width = max_w;
+ ctx->q_data[V4L2_M2M_SRC].height = max_h;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+ ctx->q_data[V4L2_M2M_DST].width = max_w;
+ ctx->q_data[V4L2_M2M_DST].height = max_h;
ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
}
@@ -868,8 +930,6 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
return -EINVAL;
}
- vb2_set_plane_payload(vb, 0, q_data->sizeimage);
-
return 0;
}
@@ -906,21 +966,34 @@ static void coda_free_framebuffers(struct coda_ctx *ctx)
}
}
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+ struct coda_dev *dev = ctx->dev;
+ u32 *p = ctx->parabuf.vaddr;
+
+ if (dev->devtype->product == CODA_DX6)
+ p[index] = value;
+ else
+ p[index ^ 1] = value;
+}
+
static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
{
struct coda_dev *dev = ctx->dev;
int height = q_data->height;
- int width = q_data->width;
- u32 *p;
+ dma_addr_t paddr;
+ int ysize;
int i;
+ ysize = round_up(q_data->width, 8) * height;
+
/* Allocate frame buffers */
ctx->num_internal_frames = CODA_MAX_FRAMEBUFFERS;
for (i = 0; i < ctx->num_internal_frames; i++) {
ctx->internal_frames[i].size = q_data->sizeimage;
if (fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6)
- ctx->internal_frames[i].size += width / 2 * height / 2;
+ ctx->internal_frames[i].size += ysize/4;
ctx->internal_frames[i].vaddr = dma_alloc_coherent(
&dev->plat_dev->dev, ctx->internal_frames[i].size,
&ctx->internal_frames[i].paddr, GFP_KERNEL);
@@ -931,32 +1004,14 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d
}
/* Register frame buffers in the parameter buffer */
- p = ctx->parabuf.vaddr;
+ for (i = 0; i < ctx->num_internal_frames; i++) {
+ paddr = ctx->internal_frames[i].paddr;
+ coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
+ coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
+ coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
- if (dev->devtype->product == CODA_DX6) {
- for (i = 0; i < ctx->num_internal_frames; i++) {
- p[i * 3] = ctx->internal_frames[i].paddr; /* Y */
- p[i * 3 + 1] = p[i * 3] + width * height; /* Cb */
- p[i * 3 + 2] = p[i * 3 + 1] + width / 2 * height / 2; /* Cr */
- }
- } else {
- for (i = 0; i < ctx->num_internal_frames; i += 2) {
- p[i * 3 + 1] = ctx->internal_frames[i].paddr; /* Y */
- p[i * 3] = p[i * 3 + 1] + width * height; /* Cb */
- p[i * 3 + 3] = p[i * 3] + (width / 2) * (height / 2); /* Cr */
-
- if (fourcc == V4L2_PIX_FMT_H264)
- p[96 + i + 1] = p[i * 3 + 3] + (width / 2) * (height / 2);
-
- if (i + 1 < ctx->num_internal_frames) {
- p[i * 3 + 2] = ctx->internal_frames[i+1].paddr; /* Y */
- p[i * 3 + 5] = p[i * 3 + 2] + width * height ; /* Cb */
- p[i * 3 + 4] = p[i * 3 + 5] + (width / 2) * (height / 2); /* Cr */
-
- if (fourcc == V4L2_PIX_FMT_H264)
- p[96 + i] = p[i * 3 + 4] + (width / 2) * (height / 2);
- }
- }
+ if (dev->devtype->product != CODA_DX6 && fourcc == V4L2_PIX_FMT_H264)
+ coda_parabuf_write(ctx, 96 + i, ctx->internal_frames[i].paddr + ysize + ysize/4 + ysize/4);
}
return 0;
@@ -980,6 +1035,28 @@ static int coda_h264_padding(int size, char *p)
return nal_size;
}
+static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
+ int header_code, u8 *header, int *size)
+{
+ struct coda_dev *dev = ctx->dev;
+ int ret;
+
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
+ CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, vb2_plane_size(buf, 0), CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
+ ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+ return ret;
+ }
+ *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(header, vb2_plane_vaddr(buf, 0), *size);
+
+ return 0;
+}
+
static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct coda_ctx *ctx = vb2_get_drv_priv(q);
@@ -990,43 +1067,38 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
struct vb2_buffer *buf;
u32 dst_fourcc;
u32 value;
- int ret;
+ int ret = 0;
if (count < 1)
return -EINVAL;
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- ctx->rawstreamon = 1;
+ ctx->streamon_out = 1;
else
- ctx->compstreamon = 1;
+ ctx->streamon_cap = 1;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ if (ctx->streamon_out) {
+ if (coda_format_is_yuv(q_data_src->fourcc))
+ ctx->inst_type = CODA_INST_ENCODER;
+ else
+ ctx->inst_type = CODA_INST_DECODER;
+ }
/* Don't start the coda unless both queues are on */
- if (!(ctx->rawstreamon & ctx->compstreamon))
+ if (!(ctx->streamon_out & ctx->streamon_cap))
return 0;
- if (coda_isbusy(dev))
- if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0)
- return -EBUSY;
-
ctx->gopcounter = ctx->params.gop_size - 1;
-
- q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
bitstream_size = q_data_dst->sizeimage;
- dst_fourcc = q_data_dst->fmt->fourcc;
-
- /* Find out whether coda must encode or decode */
- if (q_data_src->fmt->type == CODA_FMT_RAW &&
- q_data_dst->fmt->type == CODA_FMT_ENC) {
- ctx->inst_type = CODA_INST_ENCODER;
- } else if (q_data_src->fmt->type == CODA_FMT_ENC &&
- q_data_dst->fmt->type == CODA_FMT_RAW) {
- ctx->inst_type = CODA_INST_DECODER;
- v4l2_err(v4l2_dev, "decoding not supported.\n");
- return -EINVAL;
- } else {
+ dst_fourcc = q_data_dst->fourcc;
+
+ ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+ q_data_dst->fourcc);
+ if (!ctx->codec) {
v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
return -EINVAL;
}
@@ -1035,6 +1107,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
v4l2_err(v4l2_dev, "coda is not initialized.\n");
return -EFAULT;
}
+
+ mutex_lock(&dev->coda_mutex);
+
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
@@ -1057,38 +1132,31 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
switch (dev->devtype->product) {
case CODA_DX6:
value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
+ value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
break;
default:
value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+ value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
}
- value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
coda_write(dev, ctx->params.framerate,
CODA_CMD_ENC_SEQ_SRC_F_RATE);
+ ctx->params.codec_mode = ctx->codec->mode;
switch (dst_fourcc) {
case V4L2_PIX_FMT_MPEG4:
- if (dev->devtype->product == CODA_DX6)
- ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4;
- else
- ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4;
-
coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
break;
case V4L2_PIX_FMT_H264:
- if (dev->devtype->product == CODA_DX6)
- ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264;
- else
- ctx->params.codec_mode = CODA7_MODE_ENCODE_H264;
-
coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
break;
default:
v4l2_err(v4l2_dev,
"dst format (0x%08x) invalid.\n", dst_fourcc);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
switch (ctx->params.slice_mode) {
@@ -1129,8 +1197,14 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
- value = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET;
- value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET;
+ if (CODA_DEFAULT_GAMMA > 0) {
+ if (dev->devtype->product == CODA_DX6)
+ value = 1 << CODADX6_OPTION_GAMMA_OFFSET;
+ else
+ value = 1 << CODA7_OPTION_GAMMA_OFFSET;
+ } else {
+ value = 0;
+ }
coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
if (dst_fourcc == V4L2_PIX_FMT_H264) {
@@ -1145,17 +1219,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
}
}
- if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+ ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
+ if (ret < 0) {
v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
- return -ETIMEDOUT;
+ goto out;
}
- if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0)
- return -EFAULT;
+ if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
+ ret = -EFAULT;
+ goto out;
+ }
ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+ goto out;
+ }
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
@@ -1167,9 +1247,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
coda_write(dev, dev->iram_paddr + 68 * 1024, CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
coda_write(dev, 0x0, CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
}
- if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+ ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
+ if (ret < 0) {
v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
- return -ETIMEDOUT;
+ goto out;
}
/* Save stream headers */
@@ -1180,33 +1261,22 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
* Get SPS in the first frame and copy it to an
* intermediate buffer.
*/
- coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
- coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE);
- if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
- v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
- return -ETIMEDOUT;
- }
- ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
- memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
- ctx->vpu_header_size[0]);
+ ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
+ &ctx->vpu_header[0][0],
+ &ctx->vpu_header_size[0]);
+ if (ret < 0)
+ goto out;
/*
* Get PPS in the first frame and copy it to an
* intermediate buffer.
*/
- coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
- coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE);
- if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
- v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
- return -ETIMEDOUT;
- }
- ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
- memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
- ctx->vpu_header_size[1]);
+ ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
+ &ctx->vpu_header[1][0],
+ &ctx->vpu_header_size[1]);
+ if (ret < 0)
+ goto out;
+
/*
* Length of H.264 headers is variable and thus it might not be
* aligned for the coda to append the encoded frame. In that is
@@ -1222,48 +1292,32 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
* Get VOS in the first frame and copy it to an
* intermediate buffer
*/
- coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
- coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE);
- if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
- v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
- return -ETIMEDOUT;
- }
- ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
- memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
- ctx->vpu_header_size[0]);
-
- coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
- coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE);
- if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
- v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
- return -ETIMEDOUT;
- }
- ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
- memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
- ctx->vpu_header_size[1]);
-
- coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
- coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE);
- if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
- v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
- return -ETIMEDOUT;
- }
- ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
- memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0),
- ctx->vpu_header_size[2]);
+ ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
+ &ctx->vpu_header[0][0],
+ &ctx->vpu_header_size[0]);
+ if (ret < 0)
+ goto out;
+
+ ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
+ &ctx->vpu_header[1][0],
+ &ctx->vpu_header_size[1]);
+ if (ret < 0)
+ goto out;
+
+ ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
+ &ctx->vpu_header[2][0],
+ &ctx->vpu_header_size[2]);
+ if (ret < 0)
+ goto out;
break;
default:
/* No more formats need to save headers at the moment */
break;
}
- return 0;
+out:
+ mutex_unlock(&dev->coda_mutex);
+ return ret;
}
static int coda_stop_streaming(struct vb2_queue *q)
@@ -1274,26 +1328,20 @@ static int coda_stop_streaming(struct vb2_queue *q)
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"%s: output\n", __func__);
- ctx->rawstreamon = 0;
+ ctx->streamon_out = 0;
} else {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"%s: capture\n", __func__);
- ctx->compstreamon = 0;
+ ctx->streamon_cap = 0;
}
/* Don't stop the coda unless both queues are off */
- if (ctx->rawstreamon || ctx->compstreamon)
+ if (ctx->streamon_out || ctx->streamon_cap)
return 0;
- if (coda_isbusy(dev)) {
- if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0) {
- v4l2_warn(&dev->v4l2_dev,
- "%s: timeout, sending SEQ_END anyway\n", __func__);
- }
- }
-
cancel_delayed_work(&dev->timeout);
+ mutex_lock(&dev->coda_mutex);
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
"%s: sent command 'SEQ_END' to coda\n", __func__);
if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
@@ -1301,6 +1349,7 @@ static int coda_stop_streaming(struct vb2_queue *q)
"CODA_COMMAND_SEQ_END failed\n");
return -ETIMEDOUT;
}
+ mutex_unlock(&dev->coda_mutex);
coda_free_framebuffers(ctx);
@@ -1431,7 +1480,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &coda_qops;
@@ -1443,7 +1492,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &coda_qops;
@@ -1484,7 +1533,7 @@ static int coda_open(struct file *file)
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&coda_queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
- int ret = PTR_ERR(ctx->m2m_ctx);
+ ret = PTR_ERR(ctx->m2m_ctx);
v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
__func__, ret);
@@ -1596,12 +1645,14 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
if (ctx == NULL) {
v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+ mutex_unlock(&dev->coda_mutex);
return IRQ_HANDLED;
}
if (ctx->aborting) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"task has been aborted\n");
+ mutex_unlock(&dev->coda_mutex);
return IRQ_HANDLED;
}
@@ -1611,8 +1662,6 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
return IRQ_NONE;
}
- complete(&dev->done);
-
src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
@@ -1660,6 +1709,8 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
"KEYFRAME" : "PFRAME");
+ mutex_unlock(&dev->coda_mutex);
+
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
return IRQ_HANDLED;
@@ -1671,12 +1722,7 @@ static void coda_timeout(struct work_struct *work)
struct coda_dev *dev = container_of(to_delayed_work(work),
struct coda_dev, timeout);
- if (completion_done(&dev->done))
- return;
-
- complete(&dev->done);
-
- v4l2_err(&dev->v4l2_dev, "CODA PIC_RUN timeout, stopping all streams\n");
+ dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout, stopping all streams\n");
mutex_lock(&dev->dev_mutex);
list_for_each_entry(ctx, &dev->instances, list) {
@@ -1684,6 +1730,10 @@ static void coda_timeout(struct work_struct *work)
v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
}
mutex_unlock(&dev->dev_mutex);
+
+ mutex_unlock(&dev->coda_mutex);
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
}
static u32 coda_supported_firmwares[] = {
@@ -1748,6 +1798,10 @@ static int coda_hw_init(struct coda_dev *dev)
}
}
+ /* Clear registers */
+ for (i = 0; i < 64; i++)
+ coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
+
/* Tell the BIT where to find everything it needs */
coda_write(dev, dev->workbuf.paddr,
CODA_REG_BIT_WORK_BUF_ADDR);
@@ -1911,16 +1965,16 @@ enum coda_platform {
static const struct coda_devtype coda_devdata[] = {
[CODA_IMX27] = {
- .firmware = "v4l-codadx6-imx27.bin",
- .product = CODA_DX6,
- .formats = codadx6_formats,
- .num_formats = ARRAY_SIZE(codadx6_formats),
+ .firmware = "v4l-codadx6-imx27.bin",
+ .product = CODA_DX6,
+ .codecs = codadx6_codecs,
+ .num_codecs = ARRAY_SIZE(codadx6_codecs),
},
[CODA_IMX53] = {
- .firmware = "v4l-coda7541-imx53.bin",
- .product = CODA_7541,
- .formats = coda7_formats,
- .num_formats = ARRAY_SIZE(coda7_formats),
+ .firmware = "v4l-coda7541-imx53.bin",
+ .product = CODA_7541,
+ .codecs = coda7_codecs,
+ .num_codecs = ARRAY_SIZE(coda7_codecs),
},
};
@@ -1962,8 +2016,6 @@ static int coda_probe(struct platform_device *pdev)
spin_lock_init(&dev->irqlock);
INIT_LIST_HEAD(&dev->instances);
INIT_DELAYED_WORK(&dev->timeout, coda_timeout);
- init_completion(&dev->done);
- complete(&dev->done);
dev->plat_dev = pdev;
dev->clk_per = devm_clk_get(&pdev->dev, "per");
@@ -1985,17 +2037,9 @@ static int coda_probe(struct platform_device *pdev)
return -ENOENT;
}
- if (devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), CODA_NAME) == NULL) {
- dev_err(&pdev->dev, "failed to request memory region\n");
- return -ENOENT;
- }
- dev->regs_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!dev->regs_base) {
- dev_err(&pdev->dev, "failed to ioremap address region\n");
- return -ENOENT;
- }
+ dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs_base))
+ return PTR_ERR(dev->regs_base);
/* IRQ */
irq = platform_get_irq(pdev, 0);
@@ -2025,6 +2069,7 @@ static int coda_probe(struct platform_device *pdev)
return ret;
mutex_init(&dev->dev_mutex);
+ mutex_init(&dev->coda_mutex);
pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
index f3f5e43c1ac2..ace0bf0a3b9c 100644
--- a/drivers/media/platform/coda.h
+++ b/drivers/media/platform/coda.h
@@ -96,16 +96,12 @@
#define CODA_CMD_ENC_SEQ_BB_START 0x180
#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184
#define CODA_CMD_ENC_SEQ_OPTION 0x188
-#define CODA_OPTION_GAMMA_OFFSET 7
-#define CODA_OPTION_GAMMA_MASK 0x01
+#define CODA7_OPTION_GAMMA_OFFSET 8
+#define CODADX6_OPTION_GAMMA_OFFSET 7
#define CODA_OPTION_LIMITQP_OFFSET 6
-#define CODA_OPTION_LIMITQP_MASK 0x01
#define CODA_OPTION_RCINTRAQP_OFFSET 5
-#define CODA_OPTION_RCINTRAQP_MASK 0x01
#define CODA_OPTION_FMO_OFFSET 4
-#define CODA_OPTION_FMO_MASK 0x01
#define CODA_OPTION_SLICEREPORT_OFFSET 1
-#define CODA_OPTION_SLICEREPORT_MASK 0x01
#define CODA_CMD_ENC_SEQ_COD_STD 0x18c
#define CODA_STD_MPEG4 0
#define CODA_STD_H263 1
@@ -117,7 +113,8 @@
#define CODADX6_PICWIDTH_OFFSET 10
#define CODADX6_PICWIDTH_MASK 0x3ff
#define CODA_PICHEIGHT_OFFSET 0
-#define CODA_PICHEIGHT_MASK 0x3ff
+#define CODADX6_PICHEIGHT_MASK 0x3ff
+#define CODA7_PICHEIGHT_MASK 0xffff
#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194
#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198
#define CODA_MP4PARAM_VERID_OFFSET 6
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index d0b375cf565f..e180ff7282d9 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -944,7 +944,7 @@ static int vpbe_display_s_fmt(struct file *file, void *priv,
cfg->interlaced = vpbe_dev->current_timings.interlaced;
if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
- cfg->pixfmt = PIXFMT_YCbCrI;
+ cfg->pixfmt = PIXFMT_YCBCRI;
/* Change of the default pixel format for both video windows */
if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
@@ -1593,31 +1593,6 @@ static int vpbe_display_release(struct file *file)
return 0;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vpbe_display_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct v4l2_dbg_match *match = &reg->match;
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- if (match->type >= 2) {
- v4l2_subdev_call(vpbe_dev->venc,
- core,
- g_register,
- reg);
- }
-
- return 0;
-}
-
-static int vpbe_display_s_register(struct file *file, void *priv,
- const struct v4l2_dbg_register *reg)
-{
- return 0;
-}
-#endif
-
/* vpbe capture ioctl operations */
static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
.vidioc_querycap = vpbe_display_querycap,
@@ -1644,10 +1619,6 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
.vidioc_s_dv_timings = vpbe_display_s_dv_timings,
.vidioc_g_dv_timings = vpbe_display_g_dv_timings,
.vidioc_enum_dv_timings = vpbe_display_enum_dv_timings,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vpbe_display_g_register,
- .vidioc_s_register = vpbe_display_s_register,
-#endif
};
static struct v4l2_file_operations vpbe_fops = {
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 396a51cbede7..6ed82e8b297b 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -119,7 +119,7 @@ static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
#define is_rgb_pixfmt(pixfmt) \
(((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888))
#define is_yc_pixfmt(pixfmt) \
- (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \
+ (((pixfmt) == PIXFMT_YCBCRI) || ((pixfmt) == PIXFMT_YCRCBI) || \
((pixfmt) == PIXFMT_NV12))
#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
@@ -360,8 +360,8 @@ static void _osd_enable_color_key(struct osd_state *sd,
osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
OSD_TRANSPVALL);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
if (sd->vpbe_type == VPBE_VERSION_3)
osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
OSD_TRANSPVALU);
@@ -813,8 +813,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
if (osd->vpbe_type == VPBE_VERSION_1)
bad_config = !is_vid_win(layer);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
bad_config = !is_vid_win(layer);
break;
case PIXFMT_RGB888:
@@ -950,9 +950,9 @@ static void _osd_set_cbcr_order(struct osd_state *sd,
* The caller must ensure that all windows using YC pixfmt use the same
* Cb/Cr order.
*/
- if (pixfmt == PIXFMT_YCbCrI)
+ if (pixfmt == PIXFMT_YCBCRI)
osd_clear(sd, OSD_MODE_CS, OSD_MODE);
- else if (pixfmt == PIXFMT_YCrCbI)
+ else if (pixfmt == PIXFMT_YCRCBI)
osd_set(sd, OSD_MODE_CS, OSD_MODE);
}
@@ -981,8 +981,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
_osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
break;
default:
@@ -1128,8 +1128,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
_osd_enable_rgb888_pixblend(sd,
OSDWIN_OSD1);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
winmd |=
(3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
break;
@@ -1508,7 +1508,7 @@ static int osd_initialize(struct osd_state *osd)
_osd_init(osd);
/* set default Cb/Cr order */
- osd->yc_pixfmt = PIXFMT_YCbCrI;
+ osd->yc_pixfmt = PIXFMT_YCBCRI;
if (osd->vpbe_type == VPBE_VERSION_3) {
/*
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
index ea82a8bd2803..cd08e5248387 100644
--- a/drivers/media/platform/davinci/vpif.c
+++ b/drivers/media/platform/davinci/vpif.c
@@ -17,30 +17,26 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/err.h>
#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
#include <linux/v4l2-dv-timings.h>
-#include <mach/hardware.h>
-
#include "vpif.h"
MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
MODULE_LICENSE("GPL");
-#define VPIF_CH0_MAX_MODES (22)
-#define VPIF_CH1_MAX_MODES (02)
-#define VPIF_CH2_MAX_MODES (15)
-#define VPIF_CH3_MAX_MODES (02)
+#define VPIF_CH0_MAX_MODES 22
+#define VPIF_CH1_MAX_MODES 2
+#define VPIF_CH2_MAX_MODES 15
+#define VPIF_CH3_MAX_MODES 2
-static resource_size_t res_len;
-static struct resource *res;
spinlock_t vpif_lock;
void __iomem *vpif_base;
@@ -423,23 +419,12 @@ EXPORT_SYMBOL(vpif_channel_getfid);
static int vpif_probe(struct platform_device *pdev)
{
- int status = 0;
+ static struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
-
- res_len = resource_size(res);
-
- res = request_mem_region(res->start, res_len, res->name);
- if (!res)
- return -EBUSY;
-
- vpif_base = ioremap(res->start, res_len);
- if (!vpif_base) {
- status = -EBUSY;
- goto fail;
- }
+ vpif_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vpif_base))
+ return PTR_ERR(vpif_base);
pm_runtime_enable(&pdev->dev);
pm_runtime_get(&pdev->dev);
@@ -447,17 +432,11 @@ static int vpif_probe(struct platform_device *pdev)
spin_lock_init(&vpif_lock);
dev_info(&pdev->dev, "vpif probe success\n");
return 0;
-
-fail:
- release_mem_region(res->start, res_len);
- return status;
}
static int vpif_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
- iounmap(vpif_base);
- release_mem_region(res->start, res_len);
return 0;
}
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 5f98df1fc8a0..5514175bbd07 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -18,28 +18,16 @@
* TODO : add support for VBI & HBI data service
* add static buffer allocation
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
+
#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
#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"
+#include "vpif_capture.h"
MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
MODULE_LICENSE("GPL");
@@ -1874,66 +1862,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
}
/*
- * 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(ch->sd, 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,
- const struct v4l2_dbg_register *reg)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(ch->sd, core, s_register, reg);
-}
-#endif
-
-/*
* vpif_log_status() - Status information
* @file: file ptr
* @priv: file handle
@@ -1974,11 +1902,6 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_query_dv_timings = vpif_query_dv_timings,
.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,
};
@@ -2092,16 +2015,13 @@ static __init int vpif_probe(struct platform_device *pdev)
}
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
- for (i = res->start; i <= res->end; i++) {
- if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
- "VPIF_Capture", (void *)
- (&vpif_obj.dev[res_idx]->channel_id))) {
- err = -EBUSY;
- for (j = 0; j < i; j++)
- free_irq(j, (void *)
- (&vpif_obj.dev[res_idx]->channel_id));
- goto vpif_int_err;
- }
+ err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
+ IRQF_SHARED, "VPIF_Capture",
+ (void *)(&vpif_obj.dev[res_idx]->
+ channel_id));
+ if (err) {
+ err = -EINVAL;
+ goto vpif_unregister;
}
res_idx++;
}
@@ -2117,7 +2037,7 @@ static __init int vpif_probe(struct platform_device *pdev)
video_device_release(ch->video_dev);
}
err = -ENOMEM;
- goto vpif_int_err;
+ goto vpif_unregister;
}
/* Initialize field of video device */
@@ -2170,6 +2090,7 @@ static __init int vpif_probe(struct platform_device *pdev)
if (!vpif_obj.sd[i]) {
vpif_err("Error registering v4l2 subdevice\n");
+ err = -ENODEV;
goto probe_subdev_out;
}
v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
@@ -2217,13 +2138,9 @@ vpif_sd_error:
/* Note: does nothing if ch->video_dev == NULL */
video_device_release(ch->video_dev);
}
-vpif_int_err:
+vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
- for (i = 0; i < res_idx; i++) {
- res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
- for (j = res->start; j <= res->end; j++)
- free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id));
- }
+
return err;
}
@@ -2235,17 +2152,19 @@ vpif_int_err:
*/
static int vpif_remove(struct platform_device *device)
{
- int i;
struct channel_obj *ch;
+ int i;
v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ kfree(vpif_obj.sd);
/* un-register device */
for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
/* Unregister video device */
video_unregister_device(ch->video_dev);
+ kfree(vpif_obj.dev[i]);
}
return 0;
}
@@ -2336,47 +2255,4 @@ static __refdata struct platform_driver vpif_driver = {
.remove = vpif_remove,
};
-/**
- * vpif_init: initialize the vpif driver
- *
- * This function registers device and driver to the kernel, requests irq
- * handler and allocates memory
- * for channel objects
- */
-static __init int vpif_init(void)
-{
- return platform_driver_register(&vpif_driver);
-}
-
-/**
- * vpif_cleanup : This function clean up the vpif capture resources
- *
- * This will un-registers device and driver to the kernel, frees
- * requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
- struct platform_device *pdev;
- struct resource *res;
- int irq_num;
- int i = 0;
-
- pdev = container_of(vpif_dev, struct platform_device, dev);
- while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
- for (irq_num = res->start; irq_num <= res->end; irq_num++)
- free_irq(irq_num,
- (void *)(&vpif_obj.dev[i]->channel_id));
- i++;
- }
-
- platform_driver_unregister(&vpif_driver);
-
- kfree(vpif_obj.sd);
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
- kfree(vpif_obj.dev[i]);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpif_init);
-module_exit(vpif_cleanup);
+module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
index 3d3c1e5cd5d4..0ebb31260369 100644
--- a/drivers/media/platform/davinci/vpif_capture.h
+++ b/drivers/media/platform/davinci/vpif_capture.h
@@ -22,11 +22,8 @@
#ifdef __KERNEL__
/* Header files */
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/davinci/vpif_types.h>
+#include <media/v4l2-device.h>
#include "vpif.h"
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 1b3fb5ca2ad4..e6e573650250 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -14,33 +14,15 @@
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
#include <linux/slab.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-
-#include <media/adv7343.h>
-#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include "vpif_display.h"
#include "vpif.h"
+#include "vpif_display.h"
MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
MODULE_LICENSE("GPL");
@@ -1518,66 +1500,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
}
/*
- * 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(ch->sd, 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,
- const struct v4l2_dbg_register *reg)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(ch->sd, core, s_register, reg);
-}
-#endif
-
-/*
* vpif_log_status() - Status information
* @file: file ptr
* @priv: file handle
@@ -1616,11 +1538,6 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_enum_dv_timings = vpif_enum_dv_timings,
.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,
};
@@ -1734,16 +1651,14 @@ static __init int vpif_probe(struct platform_device *pdev)
}
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
- for (i = res->start; i <= res->end; i++) {
- if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
- "VPIF_Display", (void *)
- (&vpif_obj.dev[res_idx]->channel_id))) {
- err = -EBUSY;
- for (j = 0; j < i; j++)
- free_irq(j, (void *)
- (&vpif_obj.dev[res_idx]->channel_id));
- goto vpif_int_err;
- }
+ err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
+ IRQF_SHARED, "VPIF_Display",
+ (void *)(&vpif_obj.dev[res_idx]->
+ channel_id));
+ if (err) {
+ err = -EINVAL;
+ vpif_err("VPIF IRQ request failed\n");
+ goto vpif_unregister;
}
res_idx++;
}
@@ -1760,7 +1675,7 @@ static __init int vpif_probe(struct platform_device *pdev)
video_device_release(ch->video_dev);
}
err = -ENOMEM;
- goto vpif_int_err;
+ goto vpif_unregister;
}
/* Initialize field of video device */
@@ -1813,6 +1728,7 @@ static __init int vpif_probe(struct platform_device *pdev)
NULL);
if (!vpif_obj.sd[i]) {
vpif_err("Error registering v4l2 subdevice\n");
+ err = -ENODEV;
goto probe_subdev_out;
}
@@ -1893,14 +1809,8 @@ vpif_sd_error:
/* Note: does nothing if ch->video_dev == NULL */
video_device_release(ch->video_dev);
}
-vpif_int_err:
+vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
- vpif_err("VPIF IRQ request failed\n");
- for (i = 0; i < res_idx; i++) {
- res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
- for (j = res->start; j <= res->end; j++)
- free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id));
- }
return err;
}
@@ -1915,6 +1825,7 @@ static int vpif_remove(struct platform_device *device)
v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ kfree(vpif_obj.sd);
/* un-register device */
for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
@@ -1923,6 +1834,7 @@ static int vpif_remove(struct platform_device *device)
video_unregister_device(ch->video_dev);
ch->video_dev = NULL;
+ kfree(vpif_obj.dev[i]);
}
return 0;
@@ -2008,37 +1920,4 @@ static __refdata struct platform_driver vpif_driver = {
.remove = vpif_remove,
};
-static __init int vpif_init(void)
-{
- return platform_driver_register(&vpif_driver);
-}
-
-/*
- * vpif_cleanup: This function un-registers device and driver to the kernel,
- * frees requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
- struct platform_device *pdev;
- struct resource *res;
- int irq_num;
- int i = 0;
-
- pdev = container_of(vpif_dev, struct platform_device, dev);
-
- while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
- for (irq_num = res->start; irq_num <= res->end; irq_num++)
- free_irq(irq_num,
- (void *)(&vpif_obj.dev[i]->channel_id));
- i++;
- }
-
- platform_driver_unregister(&vpif_driver);
- kfree(vpif_obj.sd);
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
- kfree(vpif_obj.dev[i]);
-}
-
-module_init(vpif_init);
-module_exit(vpif_cleanup);
+module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h
index a5a18f74395c..5d87fc86e580 100644
--- a/drivers/media/platform/davinci/vpif_display.h
+++ b/drivers/media/platform/davinci/vpif_display.h
@@ -17,11 +17,8 @@
#define DAVINCIHD_DISPLAY_H
/* Header files */
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/davinci/vpif_types.h>
+#include <media/v4l2-device.h>
#include "vpif.h"
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 33b5ffc8d66d..559fab2a2d67 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -988,7 +988,7 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
if (pdev->dev.of_node) {
const struct of_device_id *match;
- match = of_match_node(of_match_ptr(exynos_gsc_match),
+ match = of_match_node(exynos_gsc_match,
pdev->dev.of_node);
if (match)
driver_data = (struct gsc_driverdata *)match->data;
diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig
index 436a62a995ee..53ad0f080179 100644
--- a/drivers/media/platform/exynos4-is/Kconfig
+++ b/drivers/media/platform/exynos4-is/Kconfig
@@ -9,12 +9,16 @@ config VIDEO_SAMSUNG_EXYNOS4_IS
if VIDEO_SAMSUNG_EXYNOS4_IS
+config VIDEO_EXYNOS4_IS_COMMON
+ tristate
+
config VIDEO_S5P_FIMC
tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
depends on I2C
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select MFD_SYSCON if OF
+ select VIDEO_EXYNOS4_IS_COMMON
help
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
interface and video postprocessor (FIMC) devices.
@@ -39,6 +43,7 @@ config VIDEO_EXYNOS_FIMC_LITE
tristate "EXYNOS FIMC-LITE camera interface driver"
depends on I2C
select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_EXYNOS4_IS_COMMON
help
This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
host interface.
diff --git a/drivers/media/platform/exynos4-is/Makefile b/drivers/media/platform/exynos4-is/Makefile
index f25f46377399..c2ff29ba6856 100644
--- a/drivers/media/platform/exynos4-is/Makefile
+++ b/drivers/media/platform/exynos4-is/Makefile
@@ -1,10 +1,13 @@
s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o media-dev.o
exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
+s5p-csis-objs := mipi-csis.o
+exynos4-is-common-objs := common.o
+
exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
-s5p-csis-objs := mipi-csis.o
obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o
obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o
obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o
+obj-$(CONFIG_VIDEO_EXYNOS4_IS_COMMON) += exynos4-is-common.o
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
new file mode 100644
index 000000000000..0ec210b4da1d
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -0,0 +1,53 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC Camera Subsystem driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@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/module.h>
+#include <media/s5p_fimc.h>
+#include "common.h"
+
+/* Called with the media graph mutex held or entity->stream_count > 0. */
+struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity)
+{
+ struct media_pad *pad = &entity->pads[0];
+ struct v4l2_subdev *sd;
+
+ while (pad->flags & MEDIA_PAD_FL_SINK) {
+ /* source pad */
+ pad = media_entity_remote_pad(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR ||
+ sd->grp_id == GRP_ID_SENSOR)
+ return sd;
+ /* sink pad */
+ pad = &sd->entity.pads[0];
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(fimc_find_remote_sensor);
+
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps)
+{
+ strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", dev_name(dev));
+ cap->device_caps = caps;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+}
+EXPORT_SYMBOL(__fimc_vidioc_querycap);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/exynos4-is/common.h b/drivers/media/platform/exynos4-is/common.h
new file mode 100644
index 000000000000..75b9c71d9419
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/common.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/videodev2.h>
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity);
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps);
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 528f41369364..fb27ff7e1e07 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -27,9 +27,10 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
-#include "media-dev.h"
+#include "common.h"
#include "fimc-core.h"
#include "fimc-reg.h"
+#include "media-dev.h"
static int fimc_capture_hw_init(struct fimc_dev *fimc)
{
@@ -119,8 +120,7 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
spin_unlock_irqrestore(&fimc->slock, flags);
if (streaming)
- return fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 0);
+ return fimc_pipeline_call(&cap->ve, set_stream, 0);
else
return 0;
}
@@ -178,8 +178,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx)
void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
{
- struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe);
+ struct v4l2_subdev *csis = p->subdevs[IDX_CSIS];
struct fimc_frame *f = &cap->ctx->d_frame;
struct fimc_vid_buffer *v_buf;
struct timeval *tv;
@@ -287,8 +288,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
fimc_activate_capture(ctx);
if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
- return fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 1);
+ return fimc_pipeline_call(&vid_cap->ve, set_stream, 1);
}
return 0;
@@ -312,7 +312,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc)
int ret = fimc_stop_capture(fimc, suspend);
if (ret)
return ret;
- return fimc_pipeline_call(fimc, close, &fimc->pipeline);
+ return fimc_pipeline_call(&fimc->vid_cap.ve, close);
}
static void buffer_queue(struct vb2_buffer *vb);
@@ -320,6 +320,7 @@ static void buffer_queue(struct vb2_buffer *vb);
int fimc_capture_resume(struct fimc_dev *fimc)
{
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct exynos_video_entity *ve = &vid_cap->ve;
struct fimc_vid_buffer *buf;
int i;
@@ -328,8 +329,7 @@ int fimc_capture_resume(struct fimc_dev *fimc)
INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
vid_cap->buf_index = 0;
- fimc_pipeline_call(fimc, open, &fimc->pipeline,
- &vid_cap->vfd.entity, false);
+ fimc_pipeline_call(ve, open, &ve->vdev.entity, false);
fimc_capture_hw_init(fimc);
clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
@@ -397,7 +397,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
unsigned long size = ctx->d_frame.payload[i];
if (vb2_plane_size(vb, i) < size) {
- v4l2_err(&ctx->fimc_dev->vid_cap.vfd,
+ v4l2_err(&ctx->fimc_dev->vid_cap.ve.vdev,
"User buffer too small (%ld < %ld)\n",
vb2_plane_size(vb, i), size);
return -EINVAL;
@@ -415,6 +415,7 @@ static void buffer_queue(struct vb2_buffer *vb)
struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct exynos_video_entity *ve = &vid_cap->ve;
unsigned long flags;
int min_bufs;
@@ -452,9 +453,9 @@ static void buffer_queue(struct vb2_buffer *vb)
if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
return;
- ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1);
+ ret = fimc_pipeline_call(ve, set_stream, 1);
if (ret < 0)
- v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret);
+ v4l2_err(&ve->vdev, "stream on failed: %d\n", ret);
return;
}
spin_unlock_irqrestore(&fimc->slock, flags);
@@ -470,44 +471,17 @@ static struct vb2_ops fimc_capture_qops = {
.stop_streaming = stop_streaming,
};
-/**
- * fimc_capture_ctrls_create - initialize the control handler
- * Initialize the capture video node control handler and fill it
- * with the FIMC controls. Inherit any sensor's controls if the
- * 'user_subdev_api' flag is false (default behaviour).
- * This function need to be called with the graph mutex held.
- */
-int fimc_capture_ctrls_create(struct fimc_dev *fimc)
-{
- struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
- struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
- int ret;
-
- if (WARN_ON(vid_cap->ctx == NULL))
- return -ENXIO;
- if (vid_cap->ctx->ctrls.ready)
- return 0;
-
- ret = fimc_ctrls_create(vid_cap->ctx);
-
- if (ret || vid_cap->user_subdev_api || !sensor ||
- !vid_cap->ctx->ctrls.ready)
- return ret;
-
- return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
- sensor->ctrl_handler, NULL);
-}
-
static int fimc_capture_set_default_format(struct fimc_dev *fimc);
static int fimc_capture_open(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct exynos_video_entity *ve = &vc->ve;
int ret = -EBUSY;
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
- fimc_md_graph_lock(fimc);
mutex_lock(&fimc->lock);
if (fimc_m2m_active(fimc))
@@ -520,31 +494,42 @@ static int fimc_capture_open(struct file *file)
ret = v4l2_fh_open(file);
if (ret) {
- pm_runtime_put(&fimc->pdev->dev);
+ pm_runtime_put_sync(&fimc->pdev->dev);
goto unlock;
}
if (v4l2_fh_is_singular_file(file)) {
- ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
- &fimc->vid_cap.vfd.entity, true);
+ fimc_md_graph_lock(ve);
- if (!ret && !fimc->vid_cap.user_subdev_api)
- ret = fimc_capture_set_default_format(fimc);
+ ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true);
- if (!ret)
- ret = fimc_capture_ctrls_create(fimc);
+ if (ret == 0 && vc->user_subdev_api && vc->inh_sensor_ctrls) {
+ /*
+ * Recreate controls of the the video node to drop
+ * any controls inherited from the sensor subdev.
+ */
+ fimc_ctrls_delete(vc->ctx);
+
+ ret = fimc_ctrls_create(vc->ctx);
+ if (ret == 0)
+ vc->inh_sensor_ctrls = false;
+ }
+ if (ret == 0)
+ ve->vdev.entity.use_count++;
+
+ fimc_md_graph_unlock(ve);
+
+ if (ret == 0)
+ ret = fimc_capture_set_default_format(fimc);
if (ret < 0) {
clear_bit(ST_CAPT_BUSY, &fimc->state);
pm_runtime_put_sync(&fimc->pdev->dev);
v4l2_fh_release(file);
- } else {
- fimc->vid_cap.refcnt++;
}
}
unlock:
mutex_unlock(&fimc->lock);
- fimc_md_graph_unlock(fimc);
return ret;
}
@@ -552,30 +537,31 @@ static int fimc_capture_release(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_vid_cap *vc = &fimc->vid_cap;
+ bool close = v4l2_fh_is_singular_file(file);
int ret;
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
mutex_lock(&fimc->lock);
- if (v4l2_fh_is_singular_file(file)) {
- if (vc->streaming) {
- media_entity_pipeline_stop(&vc->vfd.entity);
- vc->streaming = false;
- }
- clear_bit(ST_CAPT_BUSY, &fimc->state);
- fimc_stop_capture(fimc, false);
- fimc_pipeline_call(fimc, close, &fimc->pipeline);
- clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
- fimc->vid_cap.refcnt--;
+ if (close && vc->streaming) {
+ media_entity_pipeline_stop(&vc->ve.vdev.entity);
+ vc->streaming = false;
}
- pm_runtime_put(&fimc->pdev->dev);
+ ret = vb2_fop_release(file);
- if (v4l2_fh_is_singular_file(file))
- fimc_ctrls_delete(fimc->vid_cap.ctx);
+ if (close) {
+ clear_bit(ST_CAPT_BUSY, &fimc->state);
+ fimc_pipeline_call(&vc->ve, close);
+ clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
- ret = vb2_fop_release(file);
+ fimc_md_graph_lock(&vc->ve);
+ vc->ve.vdev.entity.use_count--;
+ fimc_md_graph_unlock(&vc->ve);
+ }
+
+ pm_runtime_put_sync(&fimc->pdev->dev);
mutex_unlock(&fimc->lock);
return ret;
@@ -773,7 +759,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me)
struct media_pad *pad = &me->pads[0];
while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (!pad)
break;
me = pad->entity;
@@ -797,7 +783,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
bool set)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+ struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe);
+ struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
struct v4l2_subdev_format sfmt;
struct v4l2_mbus_framefmt *mf = &sfmt.format;
struct media_entity *me;
@@ -845,7 +832,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
return ret;
}
- pad = media_entity_remote_source(&me->pads[sfmt.pad]);
+ pad = media_entity_remote_pad(&me->pads[sfmt.pad]);
if (!pad)
return -EINVAL;
me = pad->entity;
@@ -929,57 +916,101 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
return 0;
}
-static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
- struct v4l2_format *f)
+/*
+ * Try or set format on the fimc.X.capture video node and additionally
+ * on the whole pipeline if @try is false.
+ * Locking: the caller must _not_ hold the graph mutex.
+ */
+static int __video_try_or_set_format(struct fimc_dev *fimc,
+ struct v4l2_format *f, bool try,
+ struct fimc_fmt **inp_fmt,
+ struct fimc_fmt **out_fmt)
{
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- struct v4l2_mbus_framefmt mf;
- struct fimc_fmt *ffmt = NULL;
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct exynos_video_entity *ve = &vc->ve;
+ struct fimc_ctx *ctx = vc->ctx;
+ unsigned int width = 0, height = 0;
int ret = 0;
- fimc_md_graph_lock(fimc);
- mutex_lock(&fimc->lock);
-
+ /* Pre-configure format at the camera input interface, for JPEG only */
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SINK_CAM);
- ctx->s_frame.f_width = pix->width;
- ctx->s_frame.f_height = pix->height;
+ if (try) {
+ width = pix->width;
+ height = pix->height;
+ } else {
+ ctx->s_frame.f_width = pix->width;
+ ctx->s_frame.f_height = pix->height;
+ }
}
- ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
- NULL, &pix->pixelformat,
- FIMC_SD_PAD_SOURCE);
- if (!ffmt) {
- ret = -EINVAL;
- goto unlock;
+
+ /* Try the format at the scaler and the DMA output */
+ *out_fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+ NULL, &pix->pixelformat,
+ FIMC_SD_PAD_SOURCE);
+ if (*out_fmt == NULL)
+ return -EINVAL;
+
+ /* Restore image width/height for JPEG (no resizing supported). */
+ if (try && fimc_jpeg_fourcc(pix->pixelformat)) {
+ pix->width = width;
+ pix->height = height;
}
- if (!fimc->vid_cap.user_subdev_api) {
- mf.width = pix->width;
- mf.height = pix->height;
- mf.code = ffmt->mbus_code;
- fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
- pix->width = mf.width;
- pix->height = mf.height;
- if (ffmt)
- pix->pixelformat = ffmt->fourcc;
+ /* Try to match format at the host and the sensor */
+ if (!vc->user_subdev_api) {
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = try ? &mbus_fmt : &fimc->vid_cap.ci_fmt;
+
+ mf->code = (*out_fmt)->mbus_code;
+ mf->width = pix->width;
+ mf->height = pix->height;
+
+ fimc_md_graph_lock(ve);
+ ret = fimc_pipeline_try_format(ctx, mf, inp_fmt, try);
+ fimc_md_graph_unlock(ve);
+
+ if (ret < 0)
+ return ret;
+
+ pix->width = mf->width;
+ pix->height = mf->height;
}
- fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix);
+ fimc_adjust_mplane_format(*out_fmt, pix->width, pix->height, pix);
- if (ffmt->flags & FMT_FLAGS_COMPRESSED)
- fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
- pix->plane_fmt, ffmt->memplanes, true);
-unlock:
- mutex_unlock(&fimc->lock);
- fimc_md_graph_unlock(fimc);
+ if ((*out_fmt)->flags & FMT_FLAGS_COMPRESSED) {
+ struct v4l2_subdev *sensor;
+
+ fimc_md_graph_lock(ve);
+
+ sensor = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);
+ if (sensor)
+ fimc_get_sensor_frame_desc(sensor, pix->plane_fmt,
+ (*out_fmt)->memplanes, try);
+ else
+ ret = -EPIPE;
+
+ fimc_md_graph_unlock(ve);
+ }
return ret;
}
+static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL;
+
+ return __video_try_or_set_format(fimc, f, true, &inp_fmt, &out_fmt);
+}
+
static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
enum fimc_color_fmt color)
{
@@ -997,57 +1028,23 @@ static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
static int __fimc_capture_set_format(struct fimc_dev *fimc,
struct v4l2_format *f)
{
- struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct fimc_ctx *ctx = vc->ctx;
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt;
struct fimc_frame *ff = &ctx->d_frame;
- struct fimc_fmt *s_fmt = NULL;
+ struct fimc_fmt *inp_fmt = NULL;
int ret, i;
if (vb2_is_busy(&fimc->vid_cap.vbq))
return -EBUSY;
- /* Pre-configure format at camera interface input, for JPEG only */
- if (fimc_jpeg_fourcc(pix->pixelformat)) {
- fimc_capture_try_format(ctx, &pix->width, &pix->height,
- NULL, &pix->pixelformat,
- FIMC_SD_PAD_SINK_CAM);
- ctx->s_frame.f_width = pix->width;
- ctx->s_frame.f_height = pix->height;
- }
- /* Try the format at the scaler and the DMA output */
- ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
- NULL, &pix->pixelformat,
- FIMC_SD_PAD_SOURCE);
- if (!ff->fmt)
- return -EINVAL;
+ ret = __video_try_or_set_format(fimc, f, false, &inp_fmt, &ff->fmt);
+ if (ret < 0)
+ return ret;
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update(ctx);
- /* Try to match format at the host and the sensor */
- if (!fimc->vid_cap.user_subdev_api) {
- mf->code = ff->fmt->mbus_code;
- mf->width = pix->width;
- mf->height = pix->height;
- ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
- if (ret)
- return ret;
-
- pix->width = mf->width;
- pix->height = mf->height;
- }
-
- fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
-
- if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) {
- ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
- pix->plane_fmt, ff->fmt->memplanes,
- true);
- if (ret < 0)
- return ret;
- }
-
for (i = 0; i < ff->fmt->memplanes; i++) {
ff->bytesperline[i] = pix->plane_fmt[i].bytesperline;
ff->payload[i] = pix->plane_fmt[i].sizeimage;
@@ -1061,8 +1058,8 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color);
/* Reset cropping and set format at the camera interface input */
- if (!fimc->vid_cap.user_subdev_api) {
- ctx->s_frame.fmt = s_fmt;
+ if (!vc->user_subdev_api) {
+ ctx->s_frame.fmt = inp_fmt;
set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
}
@@ -1074,37 +1071,28 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
struct fimc_dev *fimc = video_drvdata(file);
- int ret;
- fimc_md_graph_lock(fimc);
- mutex_lock(&fimc->lock);
- /*
- * The graph is walked within __fimc_capture_set_format() to set
- * the format at subdevs thus the graph mutex needs to be held at
- * this point and acquired before the video mutex, to avoid AB-BA
- * deadlock when fimc_md_link_notify() is called by other thread.
- * Ideally the graph walking and setting format at the whole pipeline
- * should be removed from this driver and handled in userspace only.
- */
- ret = __fimc_capture_set_format(fimc, f);
-
- mutex_unlock(&fimc->lock);
- fimc_md_graph_unlock(fimc);
- return ret;
+ return __fimc_capture_set_format(fimc, f);
}
static int fimc_cap_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+ struct exynos_video_entity *ve = &fimc->vid_cap.ve;
+ struct v4l2_subdev *sd;
if (i->index != 0)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
+ fimc_md_graph_lock(ve);
+ sd = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);
+ fimc_md_graph_unlock(ve);
+
if (sd)
strlcpy(i->name, sd->name, sizeof(i->name));
+
return 0;
}
@@ -1130,6 +1118,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
struct v4l2_subdev_format sink_fmt, src_fmt;
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct v4l2_subdev *sd = &vc->subdev;
+ struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe);
struct media_pad *sink_pad, *src_pad;
int i, ret;
@@ -1146,7 +1135,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
if (p->flags & MEDIA_PAD_FL_SINK) {
sink_pad = p;
- src_pad = media_entity_remote_source(sink_pad);
+ src_pad = media_entity_remote_pad(sink_pad);
if (src_pad)
break;
}
@@ -1183,7 +1172,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
src_fmt.format.code != sink_fmt.format.code)
return -EPIPE;
- if (sd == fimc->pipeline.subdevs[IDX_SENSOR] &&
+ if (sd == p->subdevs[IDX_SENSOR] &&
fimc_user_defined_mbus_fmt(src_fmt.format.code)) {
struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES];
struct fimc_frame *frame = &vc->ctx->d_frame;
@@ -1207,9 +1196,8 @@ static int fimc_cap_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_pipeline *p = &fimc->pipeline;
struct fimc_vid_cap *vc = &fimc->vid_cap;
- struct media_entity *entity = &vc->vfd.entity;
+ struct media_entity *entity = &vc->ve.vdev.entity;
struct fimc_source_info *si = NULL;
struct v4l2_subdev *sd;
int ret;
@@ -1217,11 +1205,11 @@ static int fimc_cap_streamon(struct file *file, void *priv,
if (fimc_capture_active(fimc))
return -EBUSY;
- ret = media_entity_pipeline_start(entity, p->m_pipeline);
+ ret = media_entity_pipeline_start(entity, &vc->ve.pipe->mp);
if (ret < 0)
return ret;
- sd = p->subdevs[IDX_SENSOR];
+ sd = __fimc_md_get_subdev(vc->ve.pipe, IDX_SENSOR);
if (sd)
si = v4l2_get_subdev_hostdata(sd);
@@ -1259,14 +1247,15 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
int ret;
ret = vb2_ioctl_streamoff(file, priv, type);
if (ret < 0)
return ret;
- media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity);
- fimc->vid_cap.streaming = false;
+ media_entity_pipeline_stop(&vc->ve.vdev.entity);
+ vc->streaming = false;
return 0;
}
@@ -1405,6 +1394,8 @@ static int fimc_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct v4l2_subdev *sensor;
if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
return -EINVAL;
@@ -1416,15 +1407,26 @@ static int fimc_link_setup(struct media_entity *entity,
local->entity->name, remote->entity->name, flags,
fimc->vid_cap.input);
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (fimc->vid_cap.input != 0)
- return -EBUSY;
- fimc->vid_cap.input = sd->grp_id;
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ fimc->vid_cap.input = 0;
return 0;
}
- fimc->vid_cap.input = 0;
- return 0;
+ if (vc->input != 0)
+ return -EBUSY;
+
+ vc->input = sd->grp_id;
+
+ if (vc->user_subdev_api || vc->inh_sensor_ctrls)
+ return 0;
+
+ /* Inherit V4L2 controls from the image sensor subdev. */
+ sensor = fimc_find_remote_sensor(&vc->subdev.entity);
+ if (sensor == NULL)
+ return 0;
+
+ return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler,
+ sensor->ctrl_handler, NULL);
}
static const struct media_entity_operations fimc_sd_media_ops = {
@@ -1720,8 +1722,8 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
struct v4l2_format fmt = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
.fmt.pix_mp = {
- .width = 640,
- .height = 480,
+ .width = FIMC_DEFAULT_WIDTH,
+ .height = FIMC_DEFAULT_HEIGHT,
.pixelformat = V4L2_PIX_FMT_YUYV,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_JPEG,
@@ -1735,10 +1737,11 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
static int fimc_register_capture_device(struct fimc_dev *fimc,
struct v4l2_device *v4l2_dev)
{
- struct video_device *vfd = &fimc->vid_cap.vfd;
+ struct video_device *vfd = &fimc->vid_cap.ve.vdev;
struct vb2_queue *q = &fimc->vid_cap.vbq;
struct fimc_ctx *ctx;
struct fimc_vid_cap *vid_cap;
+ struct fimc_fmt *fmt;
int ret = -ENOMEM;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -1784,22 +1787,34 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
ret = vb2_queue_init(q);
if (ret)
- goto err_ent;
+ goto err_free_ctx;
+
+ /* Default format configuration */
+ fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+ vid_cap->ci_fmt.width = FIMC_DEFAULT_WIDTH;
+ vid_cap->ci_fmt.height = FIMC_DEFAULT_HEIGHT;
+ vid_cap->ci_fmt.code = fmt->mbus_code;
+
+ ctx->s_frame.width = FIMC_DEFAULT_WIDTH;
+ ctx->s_frame.height = FIMC_DEFAULT_HEIGHT;
+ ctx->s_frame.fmt = fmt;
+
+ fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_WRITEBACK, 0);
+ vid_cap->wb_fmt = vid_cap->ci_fmt;
+ vid_cap->wb_fmt.code = fmt->mbus_code;
vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
if (ret)
- goto err_ent;
- /*
- * For proper order of acquiring/releasing the video
- * and the graph mutex.
- */
- v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT);
- v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT);
+ goto err_free_ctx;
+
+ ret = fimc_ctrls_create(ctx);
+ if (ret)
+ goto err_me_cleanup;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret)
- goto err_vd;
+ goto err_ctrl_free;
v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
vfd->name, video_device_node_name(vfd));
@@ -1807,9 +1822,11 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
vfd->ctrl_handler = &ctx->ctrls.handler;
return 0;
-err_vd:
+err_ctrl_free:
+ fimc_ctrls_delete(ctx);
+err_me_cleanup:
media_entity_cleanup(&vfd->entity);
-err_ent:
+err_free_ctx:
kfree(ctx);
return ret;
}
@@ -1826,12 +1843,12 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
if (ret)
return ret;
- fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+ fimc->vid_cap.ve.pipe = v4l2_get_subdev_hostdata(sd);
ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
if (ret) {
fimc_unregister_m2m_device(fimc);
- fimc->pipeline_ops = NULL;
+ fimc->vid_cap.ve.pipe = NULL;
}
return ret;
@@ -1840,19 +1857,26 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+ struct video_device *vdev;
if (fimc == NULL)
return;
+ mutex_lock(&fimc->lock);
+
fimc_unregister_m2m_device(fimc);
+ vdev = &fimc->vid_cap.ve.vdev;
- if (video_is_registered(&fimc->vid_cap.vfd)) {
- video_unregister_device(&fimc->vid_cap.vfd);
- media_entity_cleanup(&fimc->vid_cap.vfd.entity);
- fimc->pipeline_ops = NULL;
+ if (video_is_registered(vdev)) {
+ video_unregister_device(vdev);
+ media_entity_cleanup(&vdev->entity);
+ fimc_ctrls_delete(fimc->vid_cap.ctx);
+ fimc->vid_cap.ve.pipe = NULL;
}
kfree(fimc->vid_cap.ctx);
fimc->vid_cap.ctx = NULL;
+
+ mutex_unlock(&fimc->lock);
}
static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index 379a5e9d52a7..6489c5160ee8 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -213,17 +213,6 @@ struct fimc_fmt *fimc_get_format(unsigned int index)
return &fimc_formats[index];
}
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
- unsigned int caps)
-{
- strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
- strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info),
- "platform:%s", dev_name(dev));
- cap->device_caps = caps;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-}
-
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
int dw, int dh, int rotation)
{
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index 539a3f71c16a..3d376faec777 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -48,6 +48,8 @@
#define FIMC_DEF_MIN_SIZE 16
#define FIMC_DEF_HEIGHT_ALIGN 2
#define FIMC_DEF_HOR_OFFS_ALIGN 1
+#define FIMC_DEFAULT_WIDTH 640
+#define FIMC_DEFAULT_HEIGHT 480
/* indices to the clocks array */
enum {
@@ -283,8 +285,8 @@ struct fimc_m2m_device {
/**
* struct fimc_vid_cap - camera capture device information
* @ctx: hardware context data
- * @vfd: video device node for camera capture mode
* @subdev: subdev exposing the FIMC processing block
+ * @ve: exynos video device entity structure
* @vd_pad: fimc video capture node pad
* @sd_pads: fimc video processing block pads
* @ci_fmt: image format at the FIMC camera input (and the scaler output)
@@ -298,15 +300,16 @@ struct fimc_m2m_device {
* @frame_count: the frame counter for statistics
* @reqbufs_count: the number of buffers requested in REQBUFS ioctl
* @input_index: input (camera sensor) index
- * @refcnt: driver's private reference counter
* @input: capture input type, grp_id of the attached subdev
* @user_subdev_api: true if subdevs are not configured by the host driver
+ * @inh_sensor_ctrls: a flag indicating v4l2 controls are inherited from
+ * an image sensor subdev
*/
struct fimc_vid_cap {
struct fimc_ctx *ctx;
struct vb2_alloc_ctx *alloc_ctx;
- struct video_device vfd;
struct v4l2_subdev subdev;
+ struct exynos_video_entity ve;
struct media_pad vd_pad;
struct media_pad sd_pads[FIMC_SD_PADS_NUM];
struct v4l2_mbus_framefmt ci_fmt;
@@ -321,9 +324,9 @@ struct fimc_vid_cap {
unsigned int reqbufs_count;
bool streaming;
int input_index;
- int refcnt;
u32 input;
bool user_subdev_api;
+ bool inh_sensor_ctrls;
};
/**
@@ -434,8 +437,6 @@ struct fimc_dev {
struct fimc_vid_cap vid_cap;
unsigned long state;
struct vb2_alloc_ctx *alloc_ctx;
- struct fimc_pipeline pipeline;
- const struct fimc_pipeline_ops *pipeline_ops;
};
/**
@@ -620,8 +621,6 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
/* fimc-core.c */
int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
- unsigned int caps);
int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
index c397777d7cbb..617a798d9235 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -96,7 +96,7 @@ static int fimc_is_i2c_resume(struct device *dev)
return clk_prepare_enable(isp_i2c->clock);
}
-UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
+static UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
fimc_is_i2c_resume, NULL);
static const struct of_device_id fimc_is_i2c_of_match[] = {
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c
index 53fe2a2b4db3..c7e7f694c6ed 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-param.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.c
@@ -38,7 +38,7 @@ static void __hw_param_copy(void *dst, void *src)
memcpy(dst, src, FIMC_IS_PARAM_MAX_SIZE);
}
-void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
+static void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
{
struct param_global_shotmode *dst, *src;
@@ -47,7 +47,7 @@ void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
__hw_param_copy(dst, src);
}
-void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
+static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
{
struct param_sensor_framerate *dst, *src;
@@ -168,8 +168,8 @@ unsigned int __get_pending_param_count(struct fimc_is *is)
unsigned int count;
spin_lock_irqsave(&is->slock, flags);
- count = hweight32(config->p_region_index1);
- count += hweight32(config->p_region_index2);
+ count = hweight32(config->p_region_index[0]);
+ count += hweight32(config->p_region_index[1]);
spin_unlock_irqrestore(&is->slock, flags);
return count;
@@ -177,31 +177,30 @@ unsigned int __get_pending_param_count(struct fimc_is *is)
int __is_hw_update_params(struct fimc_is *is)
{
- unsigned long *p_index1, *p_index2;
+ unsigned long *p_index;
int i, id, ret = 0;
id = is->config_index;
- p_index1 = &is->config[id].p_region_index1;
- p_index2 = &is->config[id].p_region_index2;
+ p_index = &is->config[id].p_region_index[0];
- if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1))
+ if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index))
__fimc_is_hw_update_param_global_shotmode(is);
- if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index1))
+ if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index))
__fimc_is_hw_update_param_sensor_framerate(is);
for (i = PARAM_ISP_CONTROL; i < PARAM_DRC_CONTROL; i++) {
- if (test_bit(i, p_index1))
+ if (test_bit(i, p_index))
ret = __fimc_is_hw_update_param(is, i);
}
for (i = PARAM_DRC_CONTROL; i < PARAM_SCALERC_CONTROL; i++) {
- if (test_bit(i, p_index1))
+ if (test_bit(i, p_index))
ret = __fimc_is_hw_update_param(is, i);
}
for (i = PARAM_FD_CONTROL; i <= PARAM_FD_CONFIG; i++) {
- if (test_bit((i - 32), p_index2))
+ if (test_bit(i, p_index))
ret = __fimc_is_hw_update_param(is, i);
}
@@ -243,7 +242,7 @@ void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
fd->otf_input.height = mf->height;
if (test_bit(PARAM_ISP_OTF_INPUT,
- &is->config[index].p_region_index1))
+ &is->config[index].p_region_index[0]))
return;
/* Update field */
@@ -368,7 +367,7 @@ void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val)
unsigned long *p_index;
struct isp_param *isp;
- p_index = &is->config[index].p_region_index1;
+ p_index = &is->config[index].p_region_index[0];
isp = &is->config[index].isp;
switch (cmd) {
@@ -415,7 +414,7 @@ void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val)
struct isp_param *isp;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index1;
+ p_index = &is->config[index].p_region_index[0];
isp = &is->config[index].isp;
switch (id) {
@@ -476,7 +475,7 @@ void __is_set_fd_control(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->control.cmd = val;
@@ -491,7 +490,7 @@ void __is_set_fd_config_maxface(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.max_number = val;
@@ -511,7 +510,7 @@ void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.roll_angle = val;
@@ -531,7 +530,7 @@ void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.yaw_angle = val;
@@ -551,7 +550,7 @@ void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.smile_mode = val;
@@ -571,7 +570,7 @@ void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.blink_mode = val;
@@ -591,7 +590,7 @@ void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.eye_detect = val;
@@ -611,7 +610,7 @@ void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.mouth_detect = val;
@@ -631,7 +630,7 @@ void __is_set_fd_config_orientation(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.orientation = val;
@@ -651,7 +650,7 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
struct fd_param *fd;
unsigned long *p_index;
- p_index = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[1];
fd = &is->config[index].fd;
fd->config.orientation_value = val;
@@ -672,7 +671,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
struct isp_param *isp;
struct drc_param *drc;
struct fd_param *fd;
- unsigned long *p_index1, *p_index2;
+ unsigned long *p_index;
unsigned int index;
index = is->config_index;
@@ -681,8 +680,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
isp = &is->config[index].isp;
drc = &is->config[index].drc;
fd = &is->config[index].fd;
- p_index1 = &is->config[index].p_region_index1;
- p_index2 = &is->config[index].p_region_index2;
+ p_index = &is->config[index].p_region_index[0];
/* Global */
global->shotmode.cmd = 1;
@@ -695,7 +693,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
- if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) {
+ if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) {
isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
@@ -738,20 +736,20 @@ void fimc_is_set_initial_params(struct fimc_is *is)
isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB;
fimc_is_set_param_bit(is, PARAM_ISP_AA);
- if (!test_bit(PARAM_ISP_FLASH, p_index1))
+ if (!test_bit(PARAM_ISP_FLASH, p_index))
__is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE,
ISP_FLASH_REDEYE_DISABLE);
- if (!test_bit(PARAM_ISP_AWB, p_index1))
+ if (!test_bit(PARAM_ISP_AWB, p_index))
__is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
- if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index1))
+ if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index))
__is_set_isp_effect(is, ISP_IMAGE_EFFECT_DISABLE);
- if (!test_bit(PARAM_ISP_ISO, p_index1))
+ if (!test_bit(PARAM_ISP_ISO, p_index))
__is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
- if (!test_bit(PARAM_ISP_ADJUST, p_index1)) {
+ if (!test_bit(PARAM_ISP_ADJUST, p_index)) {
__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 0);
__is_set_isp_adjust(is,
ISP_ADJUST_COMMAND_MANUAL_SATURATION, 0);
@@ -762,7 +760,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 0);
}
- if (!test_bit(PARAM_ISP_METERING, p_index1)) {
+ if (!test_bit(PARAM_ISP_METERING, p_index)) {
__is_set_isp_metering(is, 0, ISP_METERING_COMMAND_CENTER);
__is_set_isp_metering(is, 1, 0);
__is_set_isp_metering(is, 2, 0);
@@ -770,11 +768,11 @@ void fimc_is_set_initial_params(struct fimc_is *is)
__is_set_isp_metering(is, 4, 0);
}
- if (!test_bit(PARAM_ISP_AFC, p_index1))
+ if (!test_bit(PARAM_ISP_AFC, p_index))
__is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
isp->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
- if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index1)) {
+ if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index)) {
isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
@@ -784,7 +782,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
isp->otf_output.order = 0;
isp->otf_output.err = OTF_OUTPUT_ERROR_NONE;
- if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index1)) {
+ if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index)) {
isp->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
isp->dma1_output.width = 0;
isp->dma1_output.height = 0;
@@ -800,7 +798,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT);
}
- if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) {
+ if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index)) {
isp->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
isp->dma2_output.width = 0;
isp->dma2_output.height = 0;
@@ -817,7 +815,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
}
/* Sensor */
- if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) {
+ if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) {
if (is->config_index == 0)
__is_set_sensor(is, 0);
}
@@ -827,7 +825,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
__is_set_drc_control(is, CONTROL_BYPASS_ENABLE);
drc->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
- if (!test_bit(PARAM_DRC_OTF_INPUT, p_index1)) {
+ if (!test_bit(PARAM_DRC_OTF_INPUT, p_index)) {
drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
@@ -850,7 +848,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT);
drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
- if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) {
+ if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index)) {
drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
@@ -865,7 +863,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
fd->control.bypass = CONTROL_BYPASS_DISABLE;
fd->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
- if (!test_bit((PARAM_FD_OTF_INPUT - 32), p_index2)) {
+ if (!test_bit(PARAM_FD_OTF_INPUT, p_index)) {
fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c
index d05eaa2c8490..63c68ec7cfa4 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-regs.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c
@@ -89,8 +89,8 @@ int fimc_is_hw_set_param(struct fimc_is *is)
mcuctl_write(is->config_index, is, MCUCTL_REG_ISSR(2));
mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3));
- mcuctl_write(config->p_region_index1, is, MCUCTL_REG_ISSR(4));
- mcuctl_write(config->p_region_index2, is, MCUCTL_REG_ISSR(5));
+ mcuctl_write(config->p_region_index[0], is, MCUCTL_REG_ISSR(4));
+ mcuctl_write(config->p_region_index[1], is, MCUCTL_REG_ISSR(5));
fimc_is_hw_set_intgr0_gd0(is);
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 0741945b79ed..967f6a939340 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -129,7 +129,7 @@ static int fimc_is_setup_clocks(struct fimc_is *is)
ATCLK_MCUISP_FREQUENCY);
}
-int fimc_is_enable_clocks(struct fimc_is *is)
+static int fimc_is_enable_clocks(struct fimc_is *is)
{
int i, ret;
@@ -149,7 +149,7 @@ int fimc_is_enable_clocks(struct fimc_is *is)
return 0;
}
-void fimc_is_disable_clocks(struct fimc_is *is)
+static void fimc_is_disable_clocks(struct fimc_is *is)
{
int i;
@@ -527,8 +527,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is)
break;
case HIC_SET_PARAMETER:
- is->config[is->config_index].p_region_index1 = 0;
- is->config[is->config_index].p_region_index2 = 0;
+ is->config[is->config_index].p_region_index[0] = 0;
+ is->config[is->config_index].p_region_index[1] = 0;
set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
pr_debug("HIC_SET_PARAMETER\n");
break;
@@ -587,8 +587,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is)
switch (is->i2h_cmd.args[0]) {
case HIC_SET_PARAMETER:
- is->config[is->config_index].p_region_index1 = 0;
- is->config[is->config_index].p_region_index2 = 0;
+ is->config[is->config_index].p_region_index[0] = 0;
+ is->config[is->config_index].p_region_index[1] = 0;
set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
break;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h
index d7db133b493f..61bb0127e19d 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.h
+++ b/drivers/media/platform/exynos4-is/fimc-is.h
@@ -33,8 +33,8 @@
#define FIMC_IS_DRV_NAME "exynos4-fimc-is"
-#define FIMC_IS_FW_FILENAME "fimc_is_fw.bin"
-#define FIMC_IS_SETFILE_6A3 "setfile.bin"
+#define FIMC_IS_FW_FILENAME "exynos4_fimc_is_fw.bin"
+#define FIMC_IS_SETFILE_6A3 "exynos4_s5k6a3_setfile.bin"
#define FIMC_IS_FW_LOAD_TIMEOUT 1000 /* ms */
#define FIMC_IS_POWER_ON_TIMEOUT 1000 /* us */
@@ -225,8 +225,7 @@ struct chain_config {
struct drc_param drc;
struct fd_param fd;
- unsigned long p_region_index1;
- unsigned long p_region_index2;
+ unsigned long p_region_index[2];
};
/**
@@ -302,10 +301,7 @@ static inline void fimc_is_set_param_bit(struct fimc_is *is, int num)
{
struct chain_config *cfg = &is->config[is->config_index];
- if (num >= 32)
- set_bit(num - 32, &cfg->p_region_index2);
- else
- set_bit(num, &cfg->p_region_index1);
+ set_bit(num, &cfg->p_region_index[0]);
}
static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd)
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 7ede30b5910f..cf520a7d7f71 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -30,8 +30,8 @@
#include "fimc-is-regs.h"
#include "fimc-is.h"
-static int debug;
-module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR);
+int fimc_isp_debug;
+module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR);
static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
{
@@ -128,57 +128,70 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
- struct fimc_is *is = fimc_isp_to_is(isp);
struct v4l2_mbus_framefmt *mf = &fmt->format;
- struct v4l2_mbus_framefmt cur_fmt;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
- fmt->format = *mf;
+ *mf = *v4l2_subdev_get_try_format(fh, fmt->pad);
return 0;
}
mf->colorspace = V4L2_COLORSPACE_SRGB;
mutex_lock(&isp->subdev_lock);
- __is_get_frame_size(is, &cur_fmt);
if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
- /* full camera input frame size */
- mf->width = cur_fmt.width + FIMC_ISP_CAC_MARGIN_WIDTH;
- mf->height = cur_fmt.height + FIMC_ISP_CAC_MARGIN_HEIGHT;
- mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ /* ISP OTF input image format */
+ *mf = isp->sink_fmt;
} else {
- /* crop size */
- mf->width = cur_fmt.width;
- mf->height = cur_fmt.height;
- mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ /* ISP OTF output image format */
+ *mf = isp->src_fmt;
+
+ if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ }
}
mutex_unlock(&isp->subdev_lock);
- v4l2_dbg(1, debug, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n",
- __func__, fmt->pad, mf->code, mf->width, mf->height);
+ isp_dbg(1, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", __func__,
+ fmt->pad, mf->code, mf->width, mf->height);
return 0;
}
static void __isp_subdev_try_format(struct fimc_isp *isp,
- struct v4l2_subdev_format *fmt)
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct v4l2_mbus_framefmt *format;
+
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN,
FIMC_ISP_SINK_WIDTH_MAX, 0,
&mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
- isp->subdev_fmt = *mf;
+ mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
} else {
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ format = v4l2_subdev_get_try_format(fh,
+ FIMC_ISP_SD_PAD_SINK);
+ else
+ format = &isp->sink_fmt;
+
/* Allow changing format only on sink pad */
- mf->width = isp->subdev_fmt.width - FIMC_ISP_CAC_MARGIN_WIDTH;
- mf->height = isp->subdev_fmt.height - FIMC_ISP_CAC_MARGIN_HEIGHT;
- mf->code = isp->subdev_fmt.code;
+ mf->width = format->width - FIMC_ISP_CAC_MARGIN_WIDTH;
+ mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT;
+
+ if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
+ mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ } else {
+ mf->code = format->code;
+ }
}
}
@@ -191,27 +204,50 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf = &fmt->format;
int ret = 0;
- v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
+ isp_dbg(1, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
__func__, fmt->pad, mf->code, mf->width, mf->height);
- mf->colorspace = V4L2_COLORSPACE_SRGB;
-
mutex_lock(&isp->subdev_lock);
- __isp_subdev_try_format(isp, fmt);
+ __isp_subdev_try_format(isp, fh, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
mf = v4l2_subdev_get_try_format(fh, fmt->pad);
*mf = fmt->format;
- mutex_unlock(&isp->subdev_lock);
- return 0;
+
+ /* Propagate format to the source pads */
+ if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+ struct v4l2_subdev_format format = *fmt;
+ unsigned int pad;
+
+ for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
+ pad < FIMC_ISP_SD_PADS_NUM; pad++) {
+ format.pad = pad;
+ __isp_subdev_try_format(isp, fh, &format);
+ mf = v4l2_subdev_get_try_format(fh, pad);
+ *mf = format.format;
+ }
+ }
+ } else {
+ if (sd->entity.stream_count == 0) {
+ if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+ struct v4l2_subdev_format format = *fmt;
+
+ isp->sink_fmt = *mf;
+
+ format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
+ __isp_subdev_try_format(isp, fh, &format);
+
+ isp->src_fmt = format.format;
+ __is_set_frame_size(is, &isp->src_fmt);
+ } else {
+ isp->src_fmt = *mf;
+ }
+ } else {
+ ret = -EBUSY;
+ }
}
- if (sd->entity.stream_count == 0)
- __is_set_frame_size(is, mf);
- else
- ret = -EBUSY;
mutex_unlock(&isp->subdev_lock);
-
return ret;
}
@@ -221,7 +257,7 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
struct fimc_is *is = fimc_isp_to_is(isp);
int ret;
- v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
+ isp_dbg(1, sd, "%s: on: %d\n", __func__, on);
if (!test_bit(IS_ST_INIT_DONE, &is->state))
return -EBUSY;
@@ -235,8 +271,8 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
return ret;
}
- v4l2_dbg(1, debug, sd, "changing mode to %d\n",
- is->config_index);
+ isp_dbg(1, sd, "changing mode to %d\n", is->config_index);
+
ret = fimc_is_itf_mode_change(is);
if (ret)
return -EINVAL;
@@ -317,8 +353,8 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
clear_bit(IS_ST_PWR_ON, &is->state);
clear_bit(IS_ST_INIT_DONE, &is->state);
is->state = 0;
- is->config[is->config_index].p_region_index1 = 0;
- is->config[is->config_index].p_region_index2 = 0;
+ is->config[is->config_index].p_region_index[0] = 0;
+ is->config[is->config_index].p_region_index[1] = 0;
set_bit(IS_ST_IDLE, &is->state);
wmb();
}
@@ -609,6 +645,22 @@ static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
.s_ctrl = fimc_is_s_ctrl,
};
+static void __isp_subdev_set_default_format(struct fimc_isp *isp)
+{
+ struct fimc_is *is = fimc_isp_to_is(isp);
+
+ isp->sink_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH +
+ FIMC_ISP_CAC_MARGIN_WIDTH;
+ isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT +
+ FIMC_ISP_CAC_MARGIN_HEIGHT;
+ isp->sink_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ isp->src_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ __is_set_frame_size(is, &isp->src_fmt);
+}
+
int fimc_isp_subdev_create(struct fimc_isp *isp)
{
const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
@@ -689,6 +741,8 @@ int fimc_isp_subdev_create(struct fimc_isp *isp)
sd->entity.ops = &fimc_is_subdev_media_ops;
v4l2_set_subdevdata(sd, isp);
+ __isp_subdev_set_default_format(isp);
+
return 0;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h
index 800aba7ab4a7..03bf95ab017b 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.h
+++ b/drivers/media/platform/exynos4-is/fimc-isp.h
@@ -26,6 +26,11 @@
#include <media/v4l2-mediabus.h>
#include <media/s5p_fimc.h>
+extern int fimc_isp_debug;
+
+#define isp_dbg(level, dev, fmt, arg...) \
+ v4l2_dbg(level, fimc_isp_debug, dev, fmt, ## arg)
+
/* FIXME: revisit these constraints */
#define FIMC_ISP_SINK_WIDTH_MIN (16 + 8)
#define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8)
@@ -118,7 +123,6 @@ struct fimc_is_video {
unsigned int frame_count;
unsigned int reqbufs_count;
int streaming;
- unsigned long payload[FIMC_ISP_MAX_PLANES];
const struct fimc_fmt *format;
};
@@ -128,15 +132,9 @@ struct fimc_is_video {
* @alloc_ctx: videobuf2 memory allocator context
* @subdev: ISP v4l2_subdev
* @subdev_pads: the ISP subdev media pads
- * @ctrl_handler: v4l2 controls handler
* @test_pattern: test pattern controls
- * @pipeline: video capture pipeline data structure
+ * @ctrls: v4l2 controls structure
* @video_lock: mutex serializing video device and the subdev operations
- * @fmt: pointer to color format description structure
- * @payload: image size in bytes (w x h x bpp)
- * @inp_frame: camera input frame structure
- * @out_frame: DMA output frame structure
- * @source_subdev_grp_id: group id of remote source subdev
* @cac_margin_x: horizontal CAC margin in pixels
* @cac_margin_y: vertical CAC margin in pixels
* @state: driver state flags
@@ -147,17 +145,14 @@ struct fimc_isp {
struct vb2_alloc_ctx *alloc_ctx;
struct v4l2_subdev subdev;
struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM];
- struct v4l2_mbus_framefmt subdev_fmt;
+ struct v4l2_mbus_framefmt src_fmt;
+ struct v4l2_mbus_framefmt sink_fmt;
struct v4l2_ctrl *test_pattern;
struct fimc_isp_ctrls ctrls;
struct mutex video_lock;
struct mutex subdev_lock;
- struct fimc_isp_frame inp_frame;
- struct fimc_isp_frame out_frame;
- unsigned int source_subdev_grp_id;
-
unsigned int cac_margin_x;
unsigned int cac_margin_y;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index 8cc0d39a2fea..72a343e3b5e8 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -2,15 +2,16 @@
* Register interface file for EXYNOS FIMC-LITE (camera interface) driver
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Author: Sylwester Nawrocki <s.nawrocki@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/bitops.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <media/s5p_fimc.h>
#include "fimc-lite-reg.h"
@@ -68,7 +69,8 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
FLITE_REG_CIGCTRL_IRQ_LASTEN |
- FLITE_REG_CIGCTRL_IRQ_STARTEN;
+ FLITE_REG_CIGCTRL_IRQ_STARTEN |
+ FLITE_REG_CIGCTRL_IRQ_ENDEN;
} else {
/* An output to the FIMC-IS */
intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
@@ -137,7 +139,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
}
if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
- v4l2_err(&dev->vfd,
+ v4l2_err(&dev->ve.vdev,
"Unsupported pixel code, falling back to %#08x\n",
src_pixfmt_map[i][0]);
}
@@ -215,6 +217,18 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev,
flite_hw_set_camera_port(dev, si->mux_id);
}
+static void flite_hw_set_pack12(struct fimc_lite *dev, int on)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+
+ cfg &= ~FLITE_REG_CIODMAFMT_PACK12;
+
+ if (on)
+ cfg |= FLITE_REG_CIODMAFMT_PACK12;
+
+ writel(cfg, dev->regs + FLITE_REG_CIODMAFMT);
+}
+
static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
{
static const u32 pixcode[4][2] = {
@@ -250,6 +264,38 @@ void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
writel(cfg, dev->regs + FLITE_REG_CIOOFF);
}
+void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf)
+{
+ unsigned int index;
+ u32 cfg;
+
+ if (dev->dd->max_dma_bufs == 1)
+ index = 0;
+ else
+ index = buf->index;
+
+ if (index == 0)
+ writel(buf->paddr, dev->regs + FLITE_REG_CIOSA);
+ else
+ writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1));
+
+ cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
+ cfg |= BIT(index);
+ writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
+}
+
+void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index)
+{
+ u32 cfg;
+
+ if (dev->dd->max_dma_bufs == 1)
+ index = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
+ cfg &= ~BIT(index);
+ writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
+}
+
/* Enable/disable output DMA, set output pixel size and offsets (composition) */
void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
bool enable)
@@ -267,6 +313,7 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
flite_hw_set_out_order(dev, f);
flite_hw_set_dma_window(dev, f);
+ flite_hw_set_pack12(dev, 0);
}
void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
index 390383941c19..10a7d7bbcc27 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
@@ -120,6 +120,9 @@
/* b0: 1 - camera B, 0 - camera A */
#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+#define FLITE_REG_CIFCNTSEQ 0x100
+#define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x)))
+
/* ----------------------------------------------------------------------------
* Function declarations
*/
@@ -142,9 +145,12 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f);
void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on);
void flite_hw_dump_regs(struct fimc_lite *dev, const char *label);
+void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf);
+void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index);
-static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr)
+static inline void flite_hw_set_dma_buf_mask(struct fimc_lite *dev, u32 mask)
{
- writel(paddr, dev->regs + FLITE_REG_CIOSA);
+ writel(mask, dev->regs + FLITE_REG_CIFCNTSEQ);
}
+
#endif /* FIMC_LITE_REG_H */
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 14bb7bc8adbe..08fbfedea90f 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1,8 +1,8 @@
/*
* Samsung EXYNOS FIMC-LITE (camera host interface) driver
*
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@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
@@ -32,6 +32,7 @@
#include <media/videobuf2-dma-contig.h>
#include <media/s5p_fimc.h>
+#include "common.h"
#include "fimc-core.h"
#include "fimc-lite.h"
#include "fimc-lite-reg.h"
@@ -43,6 +44,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
{
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
@@ -51,6 +53,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
@@ -59,6 +62,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
@@ -67,6 +71,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
@@ -75,6 +80,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "RAW8 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 8 },
.color = FIMC_FMT_RAW8,
.memplanes = 1,
@@ -83,6 +89,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 10 },
.color = FIMC_FMT_RAW10,
.memplanes = 1,
@@ -91,6 +98,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
}, {
.name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 12 },
.color = FIMC_FMT_RAW12,
.memplanes = 1,
@@ -131,30 +139,6 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
return def_fmt;
}
-/* Called with the media graph mutex held or @me stream_count > 0. */
-static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
-{
- struct media_pad *pad = &me->pads[0];
- struct v4l2_subdev *sd;
-
- while (pad->flags & MEDIA_PAD_FL_SINK) {
- /* source pad */
- pad = media_entity_remote_source(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
-
- sd = media_entity_to_v4l2_subdev(pad->entity);
-
- if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR ||
- sd->grp_id == GRP_ID_SENSOR)
- return sd;
- /* sink pad */
- pad = &sd->entity.pads[0];
- }
- return NULL;
-}
-
static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
{
struct fimc_source_info *si;
@@ -176,6 +160,7 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
flite_hw_set_camera_bus(fimc, si);
flite_hw_set_source_format(fimc, &fimc->inp_frame);
flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+ flite_hw_set_dma_buf_mask(fimc, 0);
flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
flite_hw_set_interrupt_mask(fimc);
flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
@@ -233,7 +218,7 @@ static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
if (!streaming)
return 0;
- return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0);
+ return fimc_pipeline_call(&fimc->ve, set_stream, 0);
}
static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
@@ -299,19 +284,23 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
test_bit(ST_FLITE_RUN, &fimc->state) &&
- !list_empty(&fimc->active_buf_q) &&
!list_empty(&fimc->pending_buf_q)) {
+ vbuf = fimc_lite_pending_queue_pop(fimc);
+ flite_hw_set_dma_buffer(fimc, vbuf);
+ fimc_lite_active_queue_add(fimc, vbuf);
+ }
+
+ if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMEND) &&
+ test_bit(ST_FLITE_RUN, &fimc->state) &&
+ !list_empty(&fimc->active_buf_q)) {
vbuf = fimc_lite_active_queue_pop(fimc);
ktime_get_ts(&ts);
tv = &vbuf->vb.v4l2_buf.timestamp;
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
+ flite_hw_mask_dma_buffer(fimc, vbuf->index);
vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
-
- vbuf = fimc_lite_pending_queue_pop(fimc);
- flite_hw_set_output_addr(fimc, vbuf->paddr);
- fimc_lite_active_queue_add(fimc, vbuf);
}
if (test_bit(ST_FLITE_CONFIG, &fimc->state))
@@ -330,10 +319,16 @@ done:
static int start_streaming(struct vb2_queue *q, unsigned int count)
{
struct fimc_lite *fimc = q->drv_priv;
+ unsigned long flags;
int ret;
+ spin_lock_irqsave(&fimc->slock, flags);
+
+ fimc->buf_index = 0;
fimc->frame_count = 0;
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
ret = fimc_lite_hw_init(fimc, false);
if (ret) {
fimc_lite_reinit(fimc, false);
@@ -347,8 +342,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
flite_hw_capture_start(fimc);
if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
- fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 1);
+ fimc_pipeline_call(&fimc->ve, set_stream, 1);
}
if (debug > 0)
flite_hw_dump_regs(fimc, __func__);
@@ -415,7 +409,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
unsigned long size = fimc->payload[i];
if (vb2_plane_size(vb, i) < size) {
- v4l2_err(&fimc->vfd,
+ v4l2_err(&fimc->ve.vdev,
"User buffer too small (%ld < %ld)\n",
vb2_plane_size(vb, i), size);
return -EINVAL;
@@ -436,10 +430,14 @@ static void buffer_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&fimc->slock, flags);
buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf->index = fimc->buf_index++;
+ if (fimc->buf_index >= fimc->reqbufs_count)
+ fimc->buf_index = 0;
+
if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
!test_bit(ST_FLITE_STREAM, &fimc->state) &&
list_empty(&fimc->active_buf_q)) {
- flite_hw_set_output_addr(fimc, buf->paddr);
+ flite_hw_set_dma_buffer(fimc, buf);
fimc_lite_active_queue_add(fimc, buf);
} else {
fimc_lite_pending_queue_add(fimc, buf);
@@ -452,8 +450,7 @@ static void buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&fimc->slock, flags);
if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
- fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 1);
+ fimc_pipeline_call(&fimc->ve, set_stream, 1);
return;
}
spin_unlock_irqrestore(&fimc->slock, flags);
@@ -481,11 +478,9 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
static int fimc_lite_open(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
- struct media_entity *me = &fimc->vfd.entity;
+ struct media_entity *me = &fimc->ve.vdev.entity;
int ret;
- mutex_lock(&me->parent->graph_mutex);
-
mutex_lock(&fimc->lock);
if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
ret = -EBUSY;
@@ -505,11 +500,18 @@ static int fimc_lite_open(struct file *file)
atomic_read(&fimc->out_path) != FIMC_IO_DMA)
goto unlock;
- ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
- me, true);
+ mutex_lock(&me->parent->graph_mutex);
+
+ ret = fimc_pipeline_call(&fimc->ve, open, me, true);
+
+ /* Mark video pipeline ending at this video node as in use. */
+ if (ret == 0)
+ me->use_count++;
+
+ mutex_unlock(&me->parent->graph_mutex);
+
if (!ret) {
fimc_lite_clear_event_counters(fimc);
- fimc->ref_count++;
goto unlock;
}
@@ -519,26 +521,29 @@ err_pm:
clear_bit(ST_FLITE_IN_USE, &fimc->state);
unlock:
mutex_unlock(&fimc->lock);
- mutex_unlock(&me->parent->graph_mutex);
return ret;
}
static int fimc_lite_release(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
+ struct media_entity *entity = &fimc->ve.vdev.entity;
mutex_lock(&fimc->lock);
if (v4l2_fh_is_singular_file(file) &&
atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
if (fimc->streaming) {
- media_entity_pipeline_stop(&fimc->vfd.entity);
+ media_entity_pipeline_stop(entity);
fimc->streaming = false;
}
- clear_bit(ST_FLITE_IN_USE, &fimc->state);
fimc_lite_stop_capture(fimc, false);
- fimc_pipeline_call(fimc, close, &fimc->pipeline);
- fimc->ref_count--;
+ fimc_pipeline_call(&fimc->ve, close);
+ clear_bit(ST_FLITE_IN_USE, &fimc->state);
+
+ mutex_lock(&entity->parent->graph_mutex);
+ entity->use_count--;
+ mutex_unlock(&entity->parent->graph_mutex);
}
vb2_fop_release(file);
@@ -562,37 +567,54 @@ static const struct v4l2_file_operations fimc_lite_fops = {
* Format and crop negotiation helpers
*/
-static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
- u32 *width, u32 *height,
- u32 *code, u32 *fourcc, int pad)
+static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
{
struct flite_drvdata *dd = fimc->dd;
- const struct fimc_fmt *fmt;
- unsigned int flags = 0;
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ const struct fimc_fmt *fmt = NULL;
+
+ if (format->pad == FLITE_SD_PAD_SINK) {
+ v4l_bound_align_image(&mf->width, 8, dd->max_width,
+ ffs(dd->out_width_align) - 1,
+ &mf->height, 0, dd->max_height, 0, 0);
+
+ fmt = fimc_lite_find_format(NULL, &mf->code, 0, 0);
+ if (WARN_ON(!fmt))
+ return NULL;
- if (pad == FLITE_SD_PAD_SINK) {
- v4l_bound_align_image(width, 8, dd->max_width,
- ffs(dd->out_width_align) - 1,
- height, 0, dd->max_height, 0, 0);
+ mf->colorspace = fmt->colorspace;
+ mf->code = fmt->mbus_code;
} else {
- v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
- ffs(dd->out_width_align) - 1,
- height, 0, fimc->inp_frame.rect.height,
- 0, 0);
- flags = fimc->inp_frame.fmt->flags;
- }
+ struct flite_frame *sink = &fimc->inp_frame;
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_rect *rect;
- fmt = fimc_lite_find_format(fourcc, code, flags, 0);
- if (WARN_ON(!fmt))
- return NULL;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ sink_fmt = v4l2_subdev_get_try_format(fh,
+ FLITE_SD_PAD_SINK);
- if (code)
- *code = fmt->mbus_code;
- if (fourcc)
- *fourcc = fmt->fourcc;
+ mf->code = sink_fmt->code;
+ mf->colorspace = sink_fmt->colorspace;
- v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
- code ? *code : 0, *width, *height);
+ rect = v4l2_subdev_get_try_crop(fh,
+ FLITE_SD_PAD_SINK);
+ } else {
+ mf->code = sink->fmt->mbus_code;
+ mf->colorspace = sink->fmt->colorspace;
+ rect = &sink->rect;
+ }
+
+ /* Allow changing format only on sink pad */
+ mf->width = rect->width;
+ mf->height = rect->height;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ v4l2_dbg(1, debug, &fimc->subdev, "code: %#x (%d), %dx%d\n",
+ mf->code, mf->colorspace, mf->width, mf->height);
return fmt;
}
@@ -637,13 +659,18 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
/*
* Video node ioctl operations
*/
-static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+static int fimc_lite_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct fimc_lite *fimc = video_drvdata(file);
+
strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
- cap->bus_info[0] = 0;
- cap->card[0] = 0;
- cap->capabilities = V4L2_CAP_STREAMING;
+ strlcpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(&fimc->pdev->dev));
+
+ cap->device_caps = V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -679,7 +706,7 @@ static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
pixm->width = frame->f_width;
pixm->height = frame->f_height;
pixm->field = V4L2_FIELD_NONE;
- pixm->colorspace = V4L2_COLORSPACE_JPEG;
+ pixm->colorspace = fmt->colorspace;
return 0;
}
@@ -722,7 +749,7 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc,
fmt->depth[0]) / 8;
pixm->num_planes = fmt->memplanes;
pixm->pixelformat = fmt->fourcc;
- pixm->colorspace = V4L2_COLORSPACE_JPEG;
+ pixm->colorspace = fmt->colorspace;
pixm->field = V4L2_FIELD_NONE;
return 0;
}
@@ -786,7 +813,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
return -EPIPE;
}
/* Retrieve format at the source pad */
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (pad == NULL ||
media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
@@ -810,14 +837,13 @@ static int fimc_lite_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_lite *fimc = video_drvdata(file);
- struct media_entity *entity = &fimc->vfd.entity;
- struct fimc_pipeline *p = &fimc->pipeline;
+ struct media_entity *entity = &fimc->ve.vdev.entity;
int ret;
if (fimc_lite_active(fimc))
return -EBUSY;
- ret = media_entity_pipeline_start(entity, p->m_pipeline);
+ ret = media_entity_pipeline_start(entity, &fimc->ve.pipe->mp);
if (ret < 0)
return ret;
@@ -825,7 +851,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
if (ret < 0)
goto err_p_stop;
- fimc->sensor = __find_remote_sensor(&fimc->subdev.entity);
+ fimc->sensor = fimc_find_remote_sensor(&fimc->subdev.entity);
ret = vb2_ioctl_streamon(file, priv, type);
if (!ret) {
@@ -848,7 +874,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv,
if (ret < 0)
return ret;
- media_entity_pipeline_stop(&fimc->vfd.entity);
+ media_entity_pipeline_stop(&fimc->ve.vdev.entity);
fimc->streaming = false;
return 0;
}
@@ -938,7 +964,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh,
}
static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
- .vidioc_querycap = fimc_vidioc_querycap_capture,
+ .vidioc_querycap = fimc_lite_querycap,
.vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane,
@@ -972,8 +998,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
__func__, remote->entity->name, local->entity->name,
flags, fimc->source_subdev_grp_id);
- mutex_lock(&fimc->lock);
-
switch (local->index) {
case FLITE_SD_PAD_SINK:
if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
@@ -1015,7 +1039,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
}
mb();
- mutex_unlock(&fimc->lock);
return ret;
}
@@ -1036,6 +1059,15 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
+static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
+ struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+ if (pad != FLITE_SD_PAD_SINK)
+ pad = FLITE_SD_PAD_SOURCE_DMA;
+
+ return v4l2_subdev_get_try_format(fh, pad);
+}
+
static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
@@ -1045,13 +1077,13 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
struct flite_frame *f = &fimc->inp_frame;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
fmt->format = *mf;
return 0;
}
- mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&fimc->lock);
+ mf->colorspace = f->fmt->colorspace;
mf->code = f->fmt->mbus_code;
if (fmt->pad == FLITE_SD_PAD_SINK) {
@@ -1080,7 +1112,6 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n",
fmt->pad, mf->code, mf->width, mf->height);
- mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&fimc->lock);
if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
@@ -1091,12 +1122,20 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
return -EBUSY;
}
- ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
- &mf->code, NULL, fmt->pad);
+ ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ struct v4l2_mbus_framefmt *src_fmt;
+
+ mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
*mf = fmt->format;
+
+ if (fmt->pad == FLITE_SD_PAD_SINK) {
+ unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
+ src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad);
+ *src_fmt = *mf;
+ }
+
mutex_unlock(&fimc->lock);
return 0;
}
@@ -1114,11 +1153,6 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
source->rect = sink->rect;
source->f_width = mf->width;
source->f_height = mf->height;
- } else {
- /* Allow changing format only on sink pad */
- mf->code = sink->fmt->mbus_code;
- mf->width = sink->rect.width;
- mf->height = sink->rect.height;
}
mutex_unlock(&fimc->lock);
@@ -1207,7 +1241,7 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
* The pipeline links are protected through entity.stream_count
* so there is no need to take the media graph mutex here.
*/
- fimc->sensor = __find_remote_sensor(&sd->entity);
+ fimc->sensor = fimc_find_remote_sensor(&sd->entity);
if (atomic_read(&fimc->out_path) != FIMC_IO_ISP)
return -ENOIOCTLCMD;
@@ -1252,13 +1286,10 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
struct vb2_queue *q = &fimc->vb_queue;
- struct video_device *vfd = &fimc->vfd;
+ struct video_device *vfd = &fimc->ve.vdev;
int ret;
memset(vfd, 0, sizeof(*vfd));
-
- fimc->inp_frame.fmt = &fimc_lite_formats[0];
- fimc->out_frame.fmt = &fimc_lite_formats[0];
atomic_set(&fimc->out_path, FIMC_IO_DMA);
snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
@@ -1295,12 +1326,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
return ret;
video_set_drvdata(vfd, fimc);
- fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+ fimc->ve.pipe = v4l2_get_subdev_hostdata(sd);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
media_entity_cleanup(&vfd->entity);
- fimc->pipeline_ops = NULL;
+ fimc->ve.pipe = NULL;
return ret;
}
@@ -1316,11 +1347,15 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
if (fimc == NULL)
return;
- if (video_is_registered(&fimc->vfd)) {
- video_unregister_device(&fimc->vfd);
- media_entity_cleanup(&fimc->vfd.entity);
- fimc->pipeline_ops = NULL;
+ mutex_lock(&fimc->lock);
+
+ if (video_is_registered(&fimc->ve.vdev)) {
+ video_unregister_device(&fimc->ve.vdev);
+ media_entity_cleanup(&fimc->ve.vdev.entity);
+ fimc->ve.pipe = NULL;
}
+
+ mutex_unlock(&fimc->lock);
}
static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
@@ -1370,6 +1405,23 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = {
.step = 1,
};
+static void fimc_lite_set_default_config(struct fimc_lite *fimc)
+{
+ struct flite_frame *sink = &fimc->inp_frame;
+ struct flite_frame *source = &fimc->out_frame;
+
+ sink->fmt = &fimc_lite_formats[0];
+ sink->f_width = FLITE_DEFAULT_WIDTH;
+ sink->f_height = FLITE_DEFAULT_HEIGHT;
+
+ sink->rect.width = FLITE_DEFAULT_WIDTH;
+ sink->rect.height = FLITE_DEFAULT_HEIGHT;
+ sink->rect.left = 0;
+ sink->rect.top = 0;
+
+ *source = *sink;
+}
+
static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
{
struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
@@ -1417,12 +1469,12 @@ static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
static void fimc_lite_clk_put(struct fimc_lite *fimc)
{
- if (IS_ERR_OR_NULL(fimc->clock))
+ if (IS_ERR(fimc->clock))
return;
clk_unprepare(fimc->clock);
clk_put(fimc->clock);
- fimc->clock = NULL;
+ fimc->clock = ERR_PTR(-EINVAL);
}
static int fimc_lite_clk_get(struct fimc_lite *fimc)
@@ -1436,7 +1488,7 @@ static int fimc_lite_clk_get(struct fimc_lite *fimc)
ret = clk_prepare(fimc->clock);
if (ret < 0) {
clk_put(fimc->clock);
- fimc->clock = NULL;
+ fimc->clock = ERR_PTR(-EINVAL);
}
return ret;
}
@@ -1461,13 +1513,14 @@ static int fimc_lite_probe(struct platform_device *pdev)
if (of_id)
drv_data = (struct flite_drvdata *)of_id->data;
fimc->index = of_alias_get_id(dev->of_node, "fimc-lite");
- } else {
- drv_data = fimc_lite_get_drvdata(pdev);
- fimc->index = pdev->id;
}
- if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS)
+ if (!drv_data || fimc->index >= drv_data->num_instances ||
+ fimc->index < 0) {
+ dev_err(dev, "Wrong %s node alias\n",
+ dev->of_node->full_name);
return -EINVAL;
+ }
fimc->dd = drv_data;
fimc->pdev = pdev;
@@ -1514,8 +1567,11 @@ static int fimc_lite_probe(struct platform_device *pdev)
ret = PTR_ERR(fimc->alloc_ctx);
goto err_pm;
}
+
pm_runtime_put(dev);
+ fimc_lite_set_default_config(fimc);
+
dev_dbg(dev, "FIMC-LITE.%d registered successfully\n",
fimc->index);
return 0;
@@ -1565,8 +1621,8 @@ static int fimc_lite_resume(struct device *dev)
return 0;
INIT_LIST_HEAD(&fimc->active_buf_q);
- fimc_pipeline_call(fimc, open, &fimc->pipeline,
- &fimc->vfd.entity, false);
+ fimc_pipeline_call(&fimc->ve, open,
+ &fimc->ve.vdev.entity, false);
fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP);
clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
@@ -1592,7 +1648,7 @@ static int fimc_lite_suspend(struct device *dev)
if (ret < 0 || !fimc_lite_active(fimc))
return ret;
- return fimc_pipeline_call(fimc, close, &fimc->pipeline);
+ return fimc_pipeline_call(&fimc->ve, close);
}
#endif /* CONFIG_PM_SLEEP */
@@ -1624,22 +1680,30 @@ static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
.out_width_align = 8,
.win_hor_offs_align = 2,
.out_hor_offs_align = 8,
+ .max_dma_bufs = 1,
+ .num_instances = 2,
};
-static struct platform_device_id fimc_lite_driver_ids[] = {
- {
- .name = "exynos-fimc-lite",
- .driver_data = (unsigned long)&fimc_lite_drvdata_exynos4,
- },
- { /* sentinel */ },
+/* EXYNOS5250 */
+static struct flite_drvdata fimc_lite_drvdata_exynos5 = {
+ .max_width = 8192,
+ .max_height = 8192,
+ .out_width_align = 8,
+ .win_hor_offs_align = 2,
+ .out_hor_offs_align = 8,
+ .max_dma_bufs = 32,
+ .num_instances = 3,
};
-MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
static const struct of_device_id flite_of_match[] = {
{
.compatible = "samsung,exynos4212-fimc-lite",
.data = &fimc_lite_drvdata_exynos4,
},
+ {
+ .compatible = "samsung,exynos5250-fimc-lite",
+ .data = &fimc_lite_drvdata_exynos5,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, flite_of_match);
@@ -1647,7 +1711,6 @@ MODULE_DEVICE_TABLE(of, flite_of_match);
static struct platform_driver fimc_lite_driver = {
.probe = fimc_lite_probe,
.remove = fimc_lite_remove,
- .id_table = fimc_lite_driver_ids,
.driver = {
.of_match_table = flite_of_match,
.name = FIMC_LITE_DRV_NAME,
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index 47da5e049247..7428b2d22b52 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -27,8 +27,10 @@
#define FIMC_LITE_DRV_NAME "exynos-fimc-lite"
#define FLITE_CLK_NAME "flite"
-#define FIMC_LITE_MAX_DEVS 2
+#define FIMC_LITE_MAX_DEVS 3
#define FLITE_REQ_BUFS_MIN 2
+#define FLITE_DEFAULT_WIDTH 640
+#define FLITE_DEFAULT_HEIGHT 480
/* Bit index definitions for struct fimc_lite::state */
enum {
@@ -48,17 +50,28 @@ enum {
#define FLITE_SD_PAD_SOURCE_ISP 2
#define FLITE_SD_PADS_NUM 3
+/**
+ * struct flite_drvdata - FIMC-LITE IP variant data structure
+ * @max_width: maximum camera interface input width in pixels
+ * @max_height: maximum camera interface input height in pixels
+ * @out_width_align: minimum output width alignment in pixels
+ * @win_hor_offs_align: minimum camera interface crop window horizontal
+ * offset alignment in pixels
+ * @out_hor_offs_align: minimum output DMA compose rectangle horizontal
+ * offset alignment in pixels
+ * @max_dma_bufs: number of output DMA buffer start address registers
+ * @num_instances: total number of FIMC-LITE IP instances available
+ */
struct flite_drvdata {
unsigned short max_width;
unsigned short max_height;
unsigned short out_width_align;
unsigned short win_hor_offs_align;
unsigned short out_hor_offs_align;
+ unsigned short max_dma_bufs;
+ unsigned short num_instances;
};
-#define fimc_lite_get_drvdata(_pdev) \
- ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
-
struct fimc_lite_events {
unsigned int data_overflow;
};
@@ -83,20 +96,22 @@ struct flite_frame {
* struct flite_buffer - video buffer structure
* @vb: vb2 buffer
* @list: list head for the buffers queue
- * @paddr: precalculated physical address
+ * @paddr: DMA buffer start address
+ * @index: DMA start address register's index
*/
struct flite_buffer {
struct vb2_buffer vb;
struct list_head list;
dma_addr_t paddr;
+ unsigned short index;
};
/**
* struct fimc_lite - fimc lite structure
* @pdev: pointer to FIMC-LITE platform device
* @dd: SoC specific driver data structure
+ * @ve: exynos video device entity structure
* @v4l2_dev: pointer to top the level v4l2_device
- * @vfd: video device node
* @fh: v4l2 file handle
* @alloc_ctx: videobuf2 memory allocator context
* @subdev: FIMC-LITE subdev
@@ -122,16 +137,16 @@ struct flite_buffer {
* @pending_buf_q: pending buffers queue head
* @active_buf_q: the queue head of buffers scheduled in hardware
* @vb_queue: vb2 buffers queue
+ * @buf_index: helps to keep track of the DMA start address register index
* @active_buf_count: number of video buffers scheduled in hardware
* @frame_count: the captured frames counter
* @reqbufs_count: the number of buffers requested with REQBUFS ioctl
- * @ref_count: driver's private reference counter
*/
struct fimc_lite {
struct platform_device *pdev;
struct flite_drvdata *dd;
+ struct exynos_video_entity ve;
struct v4l2_device *v4l2_dev;
- struct video_device vfd;
struct v4l2_fh fh;
struct vb2_alloc_ctx *alloc_ctx;
struct v4l2_subdev subdev;
@@ -141,8 +156,6 @@ struct fimc_lite {
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *test_pattern;
int index;
- struct fimc_pipeline pipeline;
- const struct fimc_pipeline_ops *pipeline_ops;
struct mutex lock;
spinlock_t slock;
@@ -161,9 +174,9 @@ struct fimc_lite {
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct vb2_queue vb_queue;
+ unsigned short buf_index;
unsigned int frame_count;
unsigned int reqbufs_count;
- int ref_count;
struct fimc_lite_events events;
bool streaming;
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index bde1f47f7ed3..8d33b68c76ba 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -27,6 +27,7 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include "common.h"
#include "fimc-core.h"
#include "fimc-reg.h"
#include "media-dev.h"
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index f079f36099de..1db8cb4c46ef 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -618,7 +618,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
}
if (i == ARRAY_SIZE(pix_desc)) {
- v4l2_err(&vc->vfd,
+ v4l2_err(&vc->ve.vdev,
"Camera color format not supported: %d\n",
vc->ci_fmt.code);
return -EINVAL;
@@ -698,7 +698,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
break;
default:
- v4l2_err(&vid_cap->vfd,
+ v4l2_err(&vid_cap->ve.vdev,
"Not supported camera pixel format: %#x\n",
vid_cap->ci_fmt.code);
return -EINVAL;
@@ -721,7 +721,8 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
WARN_ONCE(1, "ISP Writeback input is not supported\n");
break;
default:
- v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n",
+ v4l2_err(&vid_cap->ve.vdev,
+ "Invalid FIMC bus type selected: %d\n",
source->fimc_bus_type);
return -EINVAL;
}
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 15ef8f28239b..19f556c5957f 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1,8 +1,8 @@
/*
* S5P/EXYNOS4 SoC series camera host interface media device driver
*
- * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@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
@@ -39,6 +39,26 @@
static int __fimc_md_set_camclk(struct fimc_md *fmd,
struct fimc_source_info *si,
bool on);
+
+/* Set up image sensor subdev -> FIMC capture node notifications. */
+static void __setup_sensor_notification(struct fimc_md *fmd,
+ struct v4l2_subdev *sensor,
+ struct v4l2_subdev *fimc_sd)
+{
+ struct fimc_source_info *src_inf;
+ struct fimc_sensor_info *md_si;
+ unsigned long flags;
+
+ src_inf = v4l2_get_subdev_hostdata(sensor);
+ if (!src_inf || WARN_ON(fmd == NULL))
+ return;
+
+ md_si = source_to_sensor_info(src_inf);
+ spin_lock_irqsave(&fmd->slock, flags);
+ md_si->host = v4l2_get_subdevdata(fimc_sd);
+ spin_unlock_irqrestore(&fmd->slock, flags);
+}
+
/**
* fimc_pipeline_prepare - update pipeline information with subdevice pointers
* @me: media entity terminating the pipeline
@@ -46,9 +66,11 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
* Caller holds the graph mutex.
*/
static void fimc_pipeline_prepare(struct fimc_pipeline *p,
- struct media_entity *me)
+ struct media_entity *me)
{
+ struct fimc_md *fmd = entity_to_fimc_mdev(me);
struct v4l2_subdev *sd;
+ struct v4l2_subdev *sensor = NULL;
int i;
for (i = 0; i < IDX_MAX; i++)
@@ -62,7 +84,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
struct media_pad *spad = &me->pads[i];
if (!(spad->flags & MEDIA_PAD_FL_SINK))
continue;
- pad = media_entity_remote_source(spad);
+ pad = media_entity_remote_pad(spad);
if (pad)
break;
}
@@ -73,8 +95,10 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
sd = media_entity_to_v4l2_subdev(pad->entity);
switch (sd->grp_id) {
- case GRP_ID_FIMC_IS_SENSOR:
case GRP_ID_SENSOR:
+ sensor = sd;
+ /* fall through */
+ case GRP_ID_FIMC_IS_SENSOR:
p->subdevs[IDX_SENSOR] = sd;
break;
case GRP_ID_CSIS:
@@ -84,7 +108,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
p->subdevs[IDX_FLITE] = sd;
break;
case GRP_ID_FIMC:
- /* No need to control FIMC subdev through subdev ops */
+ p->subdevs[IDX_FIMC] = sd;
break;
case GRP_ID_FIMC_IS:
p->subdevs[IDX_IS_ISP] = sd;
@@ -96,6 +120,9 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
if (me->num_pads == 1)
break;
}
+
+ if (sensor && p->subdevs[IDX_FIMC])
+ __setup_sensor_notification(fmd, sensor, p->subdevs[IDX_FIMC]);
}
/**
@@ -168,10 +195,11 @@ error:
*
* Called with the graph mutex held.
*/
-static int __fimc_pipeline_open(struct fimc_pipeline *p,
+static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
struct media_entity *me, bool prepare)
{
struct fimc_md *fmd = entity_to_fimc_mdev(me);
+ struct fimc_pipeline *p = to_fimc_pipeline(ep);
struct v4l2_subdev *sd;
int ret;
@@ -214,20 +242,21 @@ err_wbclk:
*
* Disable power of all subdevs and turn the external sensor clock off.
*/
-static int __fimc_pipeline_close(struct fimc_pipeline *p)
+static int __fimc_pipeline_close(struct exynos_media_pipeline *ep)
{
+ struct fimc_pipeline *p = to_fimc_pipeline(ep);
struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL;
struct fimc_md *fmd;
- int ret = 0;
-
- if (WARN_ON(sd == NULL))
- return -EINVAL;
+ int ret;
- if (p->subdevs[IDX_SENSOR]) {
- ret = fimc_pipeline_s_power(p, 0);
- fimc_md_set_camclk(sd, false);
+ if (sd == NULL) {
+ pr_warn("%s(): No sensor subdev\n", __func__);
+ return 0;
}
+ ret = fimc_pipeline_s_power(p, 0);
+ fimc_md_set_camclk(sd, false);
+
fmd = entity_to_fimc_mdev(&sd->entity);
/* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
@@ -242,12 +271,13 @@ static int __fimc_pipeline_close(struct fimc_pipeline *p)
* @pipeline: video pipeline structure
* @on: passed as the s_stream() callback argument
*/
-static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
+static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
{
static const u8 seq[2][IDX_MAX] = {
{ IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE },
{ IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
};
+ struct fimc_pipeline *p = to_fimc_pipeline(ep);
int i, ret = 0;
if (p->subdevs[IDX_SENSOR] == NULL)
@@ -271,12 +301,38 @@ error:
}
/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
-static const struct fimc_pipeline_ops fimc_pipeline_ops = {
+static const struct exynos_media_pipeline_ops fimc_pipeline_ops = {
.open = __fimc_pipeline_open,
.close = __fimc_pipeline_close,
.set_stream = __fimc_pipeline_s_stream,
};
+static struct exynos_media_pipeline *fimc_md_pipeline_create(
+ struct fimc_md *fmd)
+{
+ struct fimc_pipeline *p;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ list_add_tail(&p->list, &fmd->pipelines);
+
+ p->ep.ops = &fimc_pipeline_ops;
+ return &p->ep;
+}
+
+static void fimc_md_pipelines_free(struct fimc_md *fmd)
+{
+ while (!list_empty(&fmd->pipelines)) {
+ struct fimc_pipeline *p;
+
+ p = list_entry(fmd->pipelines.next, typeof(*p), list);
+ list_del(&p->list);
+ kfree(p);
+ }
+}
+
/*
* Sensor subdevice helper functions
*/
@@ -592,6 +648,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
struct fimc_lite *fimc_lite)
{
struct v4l2_subdev *sd;
+ struct exynos_media_pipeline *ep;
int ret;
if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS ||
@@ -600,7 +657,12 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
sd = &fimc_lite->subdev;
sd->grp_id = GRP_ID_FLITE;
- v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
+
+ ep = fimc_md_pipeline_create(fmd);
+ if (!ep)
+ return -ENOMEM;
+
+ v4l2_set_subdev_hostdata(sd, ep);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (!ret)
@@ -614,6 +676,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
{
struct v4l2_subdev *sd;
+ struct exynos_media_pipeline *ep;
int ret;
if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id]))
@@ -621,7 +684,12 @@ static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
sd = &fimc->vid_cap.subdev;
sd->grp_id = GRP_ID_FIMC;
- v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
+
+ ep = fimc_md_pipeline_create(fmd);
+ if (!ep)
+ return -ENOMEM;
+
+ v4l2_set_subdev_hostdata(sd, ep);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (!ret) {
@@ -736,8 +804,6 @@ static int fimc_md_pdev_match(struct device *dev, void *data)
if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) {
plat_entity = IDX_CSIS;
- } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) {
- plat_entity = IDX_FLITE;
} else {
p = strstr(pdev->name, "fimc");
if (p && *(p + 4) == 0)
@@ -797,17 +863,19 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
int i;
for (i = 0; i < FIMC_MAX_DEVS; i++) {
- if (fmd->fimc[i] == NULL)
+ struct fimc_dev *dev = fmd->fimc[i];
+ if (dev == NULL)
continue;
- v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
- fmd->fimc[i]->pipeline_ops = NULL;
+ v4l2_device_unregister_subdev(&dev->vid_cap.subdev);
+ dev->vid_cap.ve.pipe = NULL;
fmd->fimc[i] = NULL;
}
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
- if (fmd->fimc_lite[i] == NULL)
+ struct fimc_lite *dev = fmd->fimc_lite[i];
+ if (dev == NULL)
continue;
- v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
- fmd->fimc_lite[i]->pipeline_ops = NULL;
+ v4l2_device_unregister_subdev(&dev->subdev);
+ dev->ve.pipe = NULL;
fmd->fimc_lite[i] = NULL;
}
for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
@@ -880,18 +948,6 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
source->name, flags ? '=' : '-', sink->name);
-
- if (flags == 0 || sensor == NULL)
- continue;
-
- if (!WARN_ON(si == NULL)) {
- unsigned long irq_flags;
- struct fimc_sensor_info *inf = source_to_sensor_info(si);
-
- spin_lock_irqsave(&fmd->slock, irq_flags);
- inf->host = fmd->fimc[i];
- spin_unlock_irqrestore(&fmd->slock, irq_flags);
- }
}
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
@@ -929,7 +985,7 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
continue;
source = &fimc->subdev.entity;
- sink = &fimc->vfd.entity;
+ sink = &fimc->ve.vdev.entity;
/* FIMC-LITE's subdev and video node */
ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
sink, 0, 0);
@@ -1066,7 +1122,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
continue;
source = &fmd->fimc[i]->vid_cap.subdev.entity;
- sink = &fmd->fimc[i]->vid_cap.vfd.entity;
+ sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity;
ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
sink, 0, flags);
@@ -1231,66 +1287,98 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
return __fimc_md_set_camclk(fmd, si, on);
}
-static int fimc_md_link_notify(struct media_pad *source,
- struct media_pad *sink, u32 flags)
+static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
{
- struct fimc_lite *fimc_lite = NULL;
- struct fimc_dev *fimc = NULL;
- struct fimc_pipeline *pipeline;
- struct v4l2_subdev *sd;
- struct mutex *lock;
- int i, ret = 0;
- int ref_count;
+ struct exynos_video_entity *ve;
+ struct fimc_pipeline *p;
+ struct video_device *vdev;
+ int ret;
- if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ vdev = media_entity_to_video_device(entity);
+ if (vdev->entity.use_count == 0)
return 0;
- sd = media_entity_to_v4l2_subdev(sink->entity);
-
- switch (sd->grp_id) {
- case GRP_ID_FLITE:
- fimc_lite = v4l2_get_subdevdata(sd);
- if (WARN_ON(fimc_lite == NULL))
- return 0;
- pipeline = &fimc_lite->pipeline;
- lock = &fimc_lite->lock;
- break;
- case GRP_ID_FIMC:
- fimc = v4l2_get_subdevdata(sd);
- if (WARN_ON(fimc == NULL))
- return 0;
- pipeline = &fimc->pipeline;
- lock = &fimc->lock;
- break;
- default:
+ ve = vdev_to_exynos_video_entity(vdev);
+ p = to_fimc_pipeline(ve->pipe);
+ /*
+ * Nothing to do if we are disabling the pipeline, some link
+ * has been disconnected and p->subdevs array is cleared now.
+ */
+ if (!enable && p->subdevs[IDX_SENSOR] == NULL)
return 0;
+
+ if (enable)
+ ret = __fimc_pipeline_open(ve->pipe, entity, true);
+ else
+ ret = __fimc_pipeline_close(ve->pipe);
+
+ if (ret == 0 && !enable)
+ memset(p->subdevs, 0, sizeof(p->subdevs));
+
+ return ret;
+}
+
+/* Locking: called with entity->parent->graph_mutex mutex held. */
+static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
+{
+ struct media_entity *entity_err = entity;
+ struct media_entity_graph graph;
+ int ret;
+
+ /*
+ * Walk current graph and call the pipeline open/close routine for each
+ * opened video node that belongs to the graph of entities connected
+ * through active links. This is needed as we cannot power on/off the
+ * subdevs in random order.
+ */
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ continue;
+
+ ret = __fimc_md_modify_pipeline(entity, enable);
+
+ if (ret < 0)
+ goto err;
}
- mutex_lock(lock);
- ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
+ return 0;
+ err:
+ media_entity_graph_walk_start(&graph, entity_err);
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- if (ref_count > 0) {
- ret = __fimc_pipeline_close(pipeline);
- if (!ret && fimc)
- fimc_ctrls_delete(fimc->vid_cap.ctx);
- }
- for (i = 0; i < IDX_MAX; i++)
- pipeline->subdevs[i] = NULL;
- } else if (ref_count > 0) {
- /*
- * Link activation. Enable power of pipeline elements only if
- * the pipeline is already in use, i.e. its video node is open.
- * Recreate the controls destroyed during the link deactivation.
- */
- ret = __fimc_pipeline_open(pipeline,
- source->entity, true);
- if (!ret && fimc)
- ret = fimc_capture_ctrls_create(fimc);
+ while ((entity_err = media_entity_graph_walk_next(&graph))) {
+ if (media_entity_type(entity_err) != MEDIA_ENT_T_DEVNODE)
+ continue;
+
+ __fimc_md_modify_pipeline(entity_err, !enable);
+
+ if (entity_err == entity)
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
+ unsigned int notification)
+{
+ struct media_entity *sink = link->sink->entity;
+ int ret = 0;
+
+ /* Before link disconnection */
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+ if (!(flags & MEDIA_LNK_FL_ENABLED))
+ ret = __fimc_md_modify_pipelines(sink, false);
+ else
+ ; /* TODO: Link state change validation */
+ /* After link activation */
+ } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ (link->flags & MEDIA_LNK_FL_ENABLED)) {
+ ret = __fimc_md_modify_pipelines(sink, true);
}
- mutex_unlock(lock);
- return ret ? -EPIPE : ret;
+ return ret ? -EPIPE : 0;
}
static ssize_t fimc_md_sysfs_show(struct device *dev,
@@ -1370,6 +1458,7 @@ static int fimc_md_probe(struct platform_device *pdev)
spin_lock_init(&fmd->slock);
fmd->pdev = pdev;
+ INIT_LIST_HEAD(&fmd->pipelines);
strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
sizeof(fmd->media_dev.model));
@@ -1457,6 +1546,7 @@ static int fimc_md_remove(struct platform_device *pdev)
return 0;
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
fimc_md_unregister_entities(fmd);
+ fimc_md_pipelines_free(fmd);
media_device_unregister(&fmd->media_dev);
fimc_md_put_clocks(fmd);
return 0;
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 44d86b61d660..62599fd7756f 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -18,6 +18,7 @@
#include <media/media-entity.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
+#include <media/s5p_fimc.h>
#include "fimc-core.h"
#include "fimc-lite.h"
@@ -40,6 +41,29 @@ enum {
FIMC_MAX_WBCLKS
};
+enum fimc_subdev_index {
+ IDX_SENSOR,
+ IDX_CSIS,
+ IDX_FLITE,
+ IDX_IS_ISP,
+ IDX_FIMC,
+ IDX_MAX,
+};
+
+/*
+ * This structure represents a chain of media entities, including a data
+ * source entity (e.g. an image sensor subdevice), a data capture entity
+ * - a video capture device node and any remaining entities.
+ */
+struct fimc_pipeline {
+ struct exynos_media_pipeline ep;
+ struct list_head list;
+ struct media_entity *vdev_entity;
+ struct v4l2_subdev *subdevs[IDX_MAX];
+};
+
+#define to_fimc_pipeline(_ep) container_of(_ep, struct fimc_pipeline, ep)
+
struct fimc_csis_info {
struct v4l2_subdev *sd;
int id;
@@ -104,17 +128,11 @@ struct fimc_md {
struct pinctrl_state *state_idle;
} pinctl;
bool user_subdev_api;
+
spinlock_t slock;
+ struct list_head pipelines;
};
-#define is_subdev_pad(pad) (pad == NULL || \
- media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
-
-#define me_subtype(me) \
- ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK))
-
-#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)
-
static inline
struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si)
{
@@ -127,14 +145,14 @@ static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
container_of(me->parent, struct fimc_md, media_dev);
}
-static inline void fimc_md_graph_lock(struct fimc_dev *fimc)
+static inline void fimc_md_graph_lock(struct exynos_video_entity *ve)
{
- mutex_lock(&fimc->vid_cap.vfd.entity.parent->graph_mutex);
+ mutex_lock(&ve->vdev.entity.parent->graph_mutex);
}
-static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
+static inline void fimc_md_graph_unlock(struct exynos_video_entity *ve)
{
- mutex_unlock(&fimc->vid_cap.vfd.entity.parent->graph_mutex);
+ mutex_unlock(&ve->vdev.entity.parent->graph_mutex);
}
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
@@ -149,4 +167,16 @@ static inline bool fimc_md_is_isp_available(struct device_node *node)
#define fimc_md_is_isp_available(node) (false)
#endif /* CONFIG_OF */
+static inline struct v4l2_subdev *__fimc_md_get_subdev(
+ struct exynos_media_pipeline *ep,
+ unsigned int index)
+{
+ struct fimc_pipeline *p = to_fimc_pipeline(ep);
+
+ if (!p || index >= IDX_MAX)
+ return NULL;
+ else
+ return p->subdevs[index];
+}
+
#endif
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 254d70fe762a..0914230b42de 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -1,8 +1,8 @@
/*
- * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
*
- * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@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
@@ -66,11 +66,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* Interrupt mask */
#define S5PCSIS_INTMSK 0x10
-#define S5PCSIS_INTMSK_EN_ALL 0xf000103f
#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31)
#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30)
#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29)
#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28)
+#define S5PCSIS_INTMSK_FRAME_START (1 << 27)
+#define S5PCSIS_INTMSK_FRAME_END (1 << 26)
#define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 12)
#define S5PCSIS_INTMSK_ERR_LOST_FS (1 << 5)
#define S5PCSIS_INTMSK_ERR_LOST_FE (1 << 4)
@@ -78,6 +79,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define S5PCSIS_INTMSK_ERR_ECC (1 << 2)
#define S5PCSIS_INTMSK_ERR_CRC (1 << 1)
#define S5PCSIS_INTMSK_ERR_UNKNOWN (1 << 0)
+#define S5PCSIS_INTMSK_EXYNOS4_EN_ALL 0xf000103f
+#define S5PCSIS_INTMSK_EXYNOS5_EN_ALL 0xfc00103f
/* Interrupt source */
#define S5PCSIS_INTSRC 0x14
@@ -88,6 +91,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28)
#define S5PCSIS_INTSRC_ODD (0x3 << 28)
#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28)
+#define S5PCSIS_INTSRC_FRAME_START (1 << 27)
+#define S5PCSIS_INTSRC_FRAME_END (1 << 26)
#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12)
#define S5PCSIS_INTSRC_ERR_LOST_FS (1 << 5)
#define S5PCSIS_INTSRC_ERR_LOST_FE (1 << 4)
@@ -151,6 +156,9 @@ static const struct s5pcsis_event s5pcsis_events[] = {
{ S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" },
{ S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" },
{ S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" },
+ /* Frame start/end */
+ { S5PCSIS_INTSRC_FRAME_START, "Frame Start" },
+ { S5PCSIS_INTSRC_FRAME_END, "Frame End" },
};
#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
@@ -159,6 +167,11 @@ struct csis_pktbuf {
unsigned int len;
};
+struct csis_drvdata {
+ /* Mask of all used interrupts in S5PCSIS_INTMSK register */
+ u32 interrupt_mask;
+};
+
/**
* struct csis_state - the driver's internal state data structure
* @lock: mutex serializing the subdev and power management operations,
@@ -171,6 +184,7 @@ struct csis_pktbuf {
* @supplies: CSIS regulator supplies
* @clock: CSIS clocks
* @irq: requested s5p-mipi-csis irq number
+ * @interrupt_mask: interrupt mask of the all used interrupts
* @flags: the state variable for power and streaming control
* @clock_frequency: device bus clock frequency
* @hs_settle: HS-RX settle time
@@ -193,6 +207,7 @@ struct csis_state {
struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
struct clk *clock[NUM_CSIS_CLOCKS];
int irq;
+ u32 interrupt_mask;
u32 flags;
u32 clk_frequency;
@@ -274,9 +289,10 @@ static const struct csis_pix_format *find_csis_format(
static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
{
u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
-
- val = on ? val | S5PCSIS_INTMSK_EN_ALL :
- val & ~S5PCSIS_INTMSK_EN_ALL;
+ if (on)
+ val |= state->interrupt_mask;
+ else
+ val &= ~state->interrupt_mask;
s5pcsis_write(state, S5PCSIS_INTMSK, val);
}
@@ -771,8 +787,12 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
#define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
#endif
+static const struct of_device_id s5pcsis_of_match[];
+
static int s5pcsis_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id;
+ const struct csis_drvdata *drv_data;
struct device *dev = &pdev->dev;
struct resource *mem_res;
struct csis_state *state;
@@ -787,10 +807,19 @@ static int s5pcsis_probe(struct platform_device *pdev)
spin_lock_init(&state->slock);
state->pdev = pdev;
- if (dev->of_node)
+ if (dev->of_node) {
+ of_id = of_match_node(s5pcsis_of_match, dev->of_node);
+ if (WARN_ON(of_id == NULL))
+ return -EINVAL;
+
+ drv_data = of_id->data;
+ state->interrupt_mask = drv_data->interrupt_mask;
+
ret = s5pcsis_parse_dt(pdev, state);
- else
+ } else {
ret = s5pcsis_get_platform_data(pdev, state);
+ }
+
if (ret < 0)
return ret;
@@ -994,9 +1023,25 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
};
+static const struct csis_drvdata exynos4_csis_drvdata = {
+ .interrupt_mask = S5PCSIS_INTMSK_EXYNOS4_EN_ALL,
+};
+
+static const struct csis_drvdata exynos5_csis_drvdata = {
+ .interrupt_mask = S5PCSIS_INTMSK_EXYNOS5_EN_ALL,
+};
+
static const struct of_device_id s5pcsis_of_match[] = {
- { .compatible = "samsung,s5pv210-csis" },
- { .compatible = "samsung,exynos4210-csis" },
+ {
+ .compatible = "samsung,s5pv210-csis",
+ .data = &exynos4_csis_drvdata,
+ }, {
+ .compatible = "samsung,exynos4210-csis",
+ .data = &exynos4_csis_drvdata,
+ }, {
+ .compatible = "samsung,exynos5250-csis",
+ .data = &exynos5_csis_drvdata,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 3a6a0dcdc3e4..221ec428a01e 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1475,7 +1475,6 @@ static struct video_device viu_template = {
.release = video_device_release,
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
- .current_norm = V4L2_STD_NTSC_M,
};
static int viu_of_probe(struct platform_device *op)
@@ -1546,6 +1545,7 @@ static int viu_of_probe(struct platform_device *op)
viu_dev->vidq.timeout.function = viu_vid_timeout;
viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
init_timer(&viu_dev->vidq.timeout);
+ viu_dev->std = V4L2_STD_NTSC_M;
viu_dev->first = 1;
/* Allocate memory for video device */
diff --git a/drivers/media/platform/indycam.c b/drivers/media/platform/indycam.c
index 548236333cce..f1d192bbcb4c 100644
--- a/drivers/media/platform/indycam.c
+++ b/drivers/media/platform/indycam.c
@@ -23,7 +23,6 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include "indycam.h"
@@ -283,20 +282,9 @@ static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* I2C-interface */
-static int indycam_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct indycam *camera = to_indycam(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
- camera->version);
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops indycam_core_ops = {
- .g_chip_ident = indycam_g_chip_ident,
.g_ctrl = indycam_g_ctrl,
.s_ctrl = indycam_s_ctrl,
};
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 758564649589..540516ca872c 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -1033,6 +1033,7 @@ static int deinterlace_probe(struct platform_device *pdev)
*vfd = deinterlace_videodev;
vfd->lock = &pcdev->dev_mutex;
+ vfd->v4l2_dev = &pcdev->v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index d030f9beae88..1f079ff33d4b 100644
--- a/drivers/media/platform/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -27,7 +27,6 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/delay.h>
@@ -469,7 +468,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
goto out;
cam->pdev = pdev;
mcam = &cam->mcam;
- mcam->chip_id = V4L2_IDENT_CAFE;
+ mcam->chip_id = MCAM_CAFE;
spin_lock_init(&mcam->dev_lock);
init_waitqueue_head(&cam->smbus_wait);
mcam->plat_power_up = cafe_ctlr_power_up;
@@ -501,6 +500,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
goto out_disable;
}
+ mcam->regs_size = pci_resource_len(pdev, 0);
ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
if (ret)
goto out_iounmap;
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 64ab91edfb81..0821ed08c122 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -23,7 +23,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <media/ov7670.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
@@ -336,7 +335,7 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
} else
mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
- if (cam->chip_id == V4L2_IDENT_CAFE)
+ if (cam->chip_id == MCAM_CAFE)
mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
}
@@ -796,7 +795,6 @@ static int __mcam_cam_reset(struct mcam_camera *cam)
*/
static int mcam_cam_init(struct mcam_camera *cam)
{
- struct v4l2_dbg_chip_ident chip;
int ret;
mutex_lock(&cam->s_mutex);
@@ -804,24 +802,8 @@ static int mcam_cam_init(struct mcam_camera *cam)
cam_warn(cam, "Cam init with device in funky state %d",
cam->state);
ret = __mcam_cam_reset(cam);
- if (ret)
- goto out;
- chip.ident = V4L2_IDENT_NONE;
- chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
- chip.match.addr = cam->sensor_addr;
- ret = sensor_call(cam, core, g_chip_ident, &chip);
- if (ret)
- goto out;
- cam->sensor_type = chip.ident;
- if (cam->sensor_type != V4L2_IDENT_OV7670) {
- cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
- ret = -EINVAL;
- goto out;
- }
-/* Get/set parameters? */
- ret = 0;
+ /* Get/set parameters? */
cam->state = S_IDLE;
-out:
mcam_ctlr_power_down(cam);
mutex_unlock(&cam->s_mutex);
return ret;
@@ -1362,6 +1344,12 @@ static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
return 0;
}
+static int mcam_vidioc_g_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+ *a = V4L2_STD_NTSC_M;
+ return 0;
+}
+
/*
* G/S_PARM. Most of this is done by the sensor, but we are
* the level which controls the number of read buffers.
@@ -1392,20 +1380,6 @@ static int mcam_vidioc_s_parm(struct file *filp, void *priv,
return ret;
}
-static int mcam_vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct mcam_camera *cam = priv;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (v4l2_chip_match_host(&chip->match)) {
- chip->ident = cam->chip_id;
- return 0;
- }
- return sensor_call(cam, core, g_chip_ident, chip);
-}
-
static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
struct v4l2_frmsizeenum *sizes)
{
@@ -1436,12 +1410,11 @@ static int mcam_vidioc_g_register(struct file *file, void *priv,
{
struct mcam_camera *cam = priv;
- if (v4l2_chip_match_host(&reg->match)) {
- reg->val = mcam_reg_read(cam, reg->reg);
- reg->size = 4;
- return 0;
- }
- return sensor_call(cam, core, g_register, reg);
+ if (reg->reg > cam->regs_size - 4)
+ return -EINVAL;
+ reg->val = mcam_reg_read(cam, reg->reg);
+ reg->size = 4;
+ return 0;
}
static int mcam_vidioc_s_register(struct file *file, void *priv,
@@ -1449,11 +1422,10 @@ static int mcam_vidioc_s_register(struct file *file, void *priv,
{
struct mcam_camera *cam = priv;
- if (v4l2_chip_match_host(&reg->match)) {
- mcam_reg_write(cam, reg->reg, reg->val);
- return 0;
- }
- return sensor_call(cam, core, s_register, reg);
+ if (reg->reg > cam->regs_size - 4)
+ return -EINVAL;
+ mcam_reg_write(cam, reg->reg, reg->val);
+ return 0;
}
#endif
@@ -1467,6 +1439,7 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
.vidioc_g_input = mcam_vidioc_g_input,
.vidioc_s_input = mcam_vidioc_s_input,
.vidioc_s_std = mcam_vidioc_s_std,
+ .vidioc_g_std = mcam_vidioc_g_std,
.vidioc_reqbufs = mcam_vidioc_reqbufs,
.vidioc_querybuf = mcam_vidioc_querybuf,
.vidioc_qbuf = mcam_vidioc_qbuf,
@@ -1477,7 +1450,6 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
.vidioc_s_parm = mcam_vidioc_s_parm,
.vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
.vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals,
- .vidioc_g_chip_ident = mcam_vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = mcam_vidioc_g_register,
.vidioc_s_register = mcam_vidioc_s_register,
@@ -1593,7 +1565,6 @@ static const struct v4l2_file_operations mcam_v4l_fops = {
static struct video_device mcam_v4l_template = {
.name = "mcam",
.tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */
.fops = &mcam_v4l_fops,
.ioctl_ops = &mcam_v4l_ioctl_ops,
@@ -1695,7 +1666,7 @@ int mccic_register(struct mcam_camera *cam)
if (buffer_mode >= 0)
cam->buffer_mode = buffer_mode;
if (cam->buffer_mode == B_DMA_sg &&
- cam->chip_id == V4L2_IDENT_CAFE) {
+ cam->chip_id == MCAM_CAFE) {
printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
"attempting vmalloc mode instead\n");
cam->buffer_mode = B_vmalloc;
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
index 01dec9e5fc2b..520c8ded9443 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.h
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
@@ -53,6 +53,11 @@ enum mcam_buffer_mode {
B_DMA_sg = 2
};
+enum mcam_chip_id {
+ MCAM_CAFE,
+ MCAM_ARMADA610,
+};
+
/*
* Is a given buffer mode supported by the current kernel configuration?
*/
@@ -96,9 +101,10 @@ struct mcam_camera {
*/
struct i2c_adapter *i2c_adapter;
unsigned char __iomem *regs;
+ unsigned regs_size; /* size in bytes of the register space */
spinlock_t dev_lock;
struct device *dev; /* For messages, dma alloc */
- unsigned int chip_id;
+ enum mcam_chip_id chip_id;
short int clock_speed; /* Sensor clock speed, default 30 */
short int use_smbus; /* SMBUS or straight I2c? */
enum mcam_buffer_mode buffer_mode;
@@ -152,7 +158,6 @@ struct mcam_camera {
void (*frame_complete)(struct mcam_camera *cam, int frame);
/* Current operating parameters */
- u32 sensor_type; /* Currently ov7670 only */
struct v4l2_pix_format pix_format;
enum v4l2_mbus_pixelcode mbus_code;
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index c4c17fe76c0d..a634888271cd 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/mmp-camera.h>
#include <linux/device.h>
#include <linux/platform_device.h>
@@ -185,7 +184,7 @@ static int mmpcam_probe(struct platform_device *pdev)
mcam->plat_power_down = mmpcam_power_down;
mcam->dev = &pdev->dev;
mcam->use_smbus = 0;
- mcam->chip_id = V4L2_IDENT_ARMADA610;
+ mcam->chip_id = MCAM_ARMADA610;
mcam->buffer_mode = B_DMA_sg;
spin_lock_init(&mcam->dev_lock);
/*
@@ -203,6 +202,7 @@ static int mmpcam_probe(struct platform_device *pdev)
ret = -ENODEV;
goto out_free;
}
+ mcam->regs_size = resource_size(res);
/*
* Power/clock memory is elsewhere; get it too. Perhaps this
* should really be managed outside of this driver?
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 4cc7f65d7d76..6a17676f9d72 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -1051,6 +1051,7 @@ static int m2mtest_probe(struct platform_device *pdev)
*vfd = m2mtest_videodev;
vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
@@ -1061,7 +1062,7 @@ static int m2mtest_probe(struct platform_device *pdev)
video_set_drvdata(vfd, dev);
snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
dev->vfd = vfd;
- v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+ v4l2_info(&dev->v4l2_dev,
"Device registered as /dev/video%d\n", vfd->num);
setup_timer(&dev->timer, device_isr, (long)dev);
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index f7440e585b6b..c690435853bd 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -937,6 +937,7 @@ static int emmaprp_probe(struct platform_device *pdev)
*vfd = emmaprp_videodev;
vfd->lock = &pcdev->dev_mutex;
+ vfd->v4l2_dev = &pcdev->v4l2_dev;
video_set_drvdata(vfd, pcdev);
snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index d338b19da544..dfd0a21a0658 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -335,8 +335,6 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
ovl = ovid->overlays[0];
switch (pix->pixelformat) {
- case 0:
- break;
case V4L2_PIX_FMT_YUYV:
mode = OMAP_DSS_COLOR_YUV2;
break;
@@ -358,6 +356,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
break;
default:
mode = -EINVAL;
+ break;
}
return mode;
}
diff --git a/drivers/media/platform/omap24xxcam.c b/drivers/media/platform/omap24xxcam.c
index debb44ceb185..d2b440c842b3 100644
--- a/drivers/media/platform/omap24xxcam.c
+++ b/drivers/media/platform/omap24xxcam.c
@@ -1656,7 +1656,7 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s)
}
vfd->release = video_device_release;
- vfd->parent = cam->dev;
+ vfd->v4l2_dev = &cam->v4l2_dev;
strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
vfd->fops = &omap24xxcam_fops;
@@ -1752,6 +1752,11 @@ static int omap24xxcam_probe(struct platform_device *pdev)
cam->dev = &pdev->dev;
+ if (v4l2_device_register(&pdev->dev, &cam->v4l2_dev)) {
+ dev_err(&pdev->dev, "v4l2_device_register failed\n");
+ goto err;
+ }
+
/*
* Impose a lower limit on the amount of memory allocated for
* capture. We require at least enough memory to double-buffer
@@ -1849,6 +1854,8 @@ static int omap24xxcam_remove(struct platform_device *pdev)
cam->mmio_base_phys = 0;
}
+ v4l2_device_unregister(&cam->v4l2_dev);
+
kfree(cam);
return 0;
diff --git a/drivers/media/platform/omap24xxcam.h b/drivers/media/platform/omap24xxcam.h
index c4395956a493..7f6f79155537 100644
--- a/drivers/media/platform/omap24xxcam.h
+++ b/drivers/media/platform/omap24xxcam.h
@@ -29,6 +29,7 @@
#include <media/videobuf-dma-sg.h>
#include <media/v4l2-int-device.h>
+#include <media/v4l2-device.h>
/*
*
@@ -462,6 +463,8 @@ struct omap24xxcam_device {
*/
struct mutex mutex;
+ struct v4l2_device v4l2_dev;
+
/*** general driver state information ***/
atomic_t users;
/*
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 1d7dbd5c0fba..df3a0ec7fd2c 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -792,9 +792,9 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
/*
* isp_pipeline_link_notify - Link management notification callback
- * @source: Pad at the start of the link
- * @sink: Pad at the end of the link
+ * @link: The link
* @flags: New link flags that will be applied
+ * @notification: The link's state change notification type (MEDIA_DEV_NOTIFY_*)
*
* React to link management on powered pipelines by updating the use count of
* all entities in the source and sink sides of the link. Entities are powered
@@ -804,29 +804,38 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
* off is assumed to never fail. This function will not fail for disconnection
* events.
*/
-static int isp_pipeline_link_notify(struct media_pad *source,
- struct media_pad *sink, u32 flags)
+static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
{
- int source_use = isp_pipeline_pm_use_count(source->entity);
- int sink_use = isp_pipeline_pm_use_count(sink->entity);
+ struct media_entity *source = link->source->entity;
+ struct media_entity *sink = link->sink->entity;
+ int source_use = isp_pipeline_pm_use_count(source);
+ int sink_use = isp_pipeline_pm_use_count(sink);
int ret;
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ !(link->flags & MEDIA_LNK_FL_ENABLED)) {
/* Powering off entities is assumed to never fail. */
- isp_pipeline_pm_power(source->entity, -sink_use);
- isp_pipeline_pm_power(sink->entity, -source_use);
+ isp_pipeline_pm_power(source, -sink_use);
+ isp_pipeline_pm_power(sink, -source_use);
return 0;
}
- ret = isp_pipeline_pm_power(source->entity, sink_use);
- if (ret < 0)
- return ret;
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ (flags & MEDIA_LNK_FL_ENABLED)) {
- ret = isp_pipeline_pm_power(sink->entity, source_use);
- if (ret < 0)
- isp_pipeline_pm_power(source->entity, -sink_use);
+ ret = isp_pipeline_pm_power(source, sink_use);
+ if (ret < 0)
+ return ret;
- return ret;
+ ret = isp_pipeline_pm_power(sink, source_use);
+ if (ret < 0)
+ isp_pipeline_pm_power(source, -sink_use);
+
+ return ret;
+ }
+
+ return 0;
}
/* -----------------------------------------------------------------------------
@@ -877,7 +886,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (pad == NULL ||
media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
@@ -967,7 +976,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (pad == NULL ||
media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
@@ -1083,7 +1092,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
pipe = to_isp_pipeline(me);
if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
return 0;
- pad = media_entity_remote_source(&pipe->output->pad);
+ pad = media_entity_remote_pad(&pipe->output->pad);
return pad->entity == me;
}
@@ -2249,6 +2258,7 @@ static int isp_probe(struct platform_device *pdev)
ret = iommu_attach_device(isp->domain, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
+ ret = -EPROBE_DEFER;
goto free_domain;
}
@@ -2287,12 +2297,11 @@ detach_dev:
iommu_detach_device(isp->domain, &pdev->dev);
free_domain:
iommu_domain_free(isp->domain);
+ isp->domain = NULL;
error_isp:
isp_xclk_cleanup(isp);
omap3isp_put(isp);
error:
- platform_set_drvdata(pdev, NULL);
-
mutex_destroy(&isp->isp_mutex);
return ret;
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 60e60aa64fb4..907a205da5a5 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1120,7 +1120,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
u32 syn_mode;
u32 ccdc_pattern;
- pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+ pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
if (ccdc->input == CCDC_INPUT_PARALLEL)
pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index c5d84c977e29..e71651429dda 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -158,13 +158,17 @@ static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
* @ccp2: pointer to ISP CCP2 device
* @enable: enable/disable flag
*/
-static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
+static int ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
{
struct isp_device *isp = to_isp_device(ccp2);
+ int ret;
int i;
- if (enable && ccp2->vdds_csib)
- regulator_enable(ccp2->vdds_csib);
+ if (enable && ccp2->vdds_csib) {
+ ret = regulator_enable(ccp2->vdds_csib);
+ if (ret < 0)
+ return ret;
+ }
/* Enable/Disable all the LCx channels */
for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
@@ -179,6 +183,8 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
if (!enable && ccp2->vdds_csib)
regulator_disable(ccp2->vdds_csib);
+
+ return 0;
}
/*
@@ -360,7 +366,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
ccp2_pwr_cfg(ccp2);
- pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]);
+ pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
pdata = sensor->host_priv;
@@ -851,7 +857,12 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
ccp2_print_status(ccp2);
/* Enable CSI1/CCP2 interface */
- ccp2_if_enable(ccp2, 1);
+ ret = ccp2_if_enable(ccp2, 1);
+ if (ret < 0) {
+ if (ccp2->phy)
+ omap3isp_csiphy_release(ccp2->phy);
+ return ret;
+ }
break;
case ISP_PIPELINE_STREAM_SINGLESHOT:
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index 783f4b05b153..6db245d84bbb 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -573,7 +573,7 @@ static int csi2_configure(struct isp_csi2_device *csi2)
if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
return -EBUSY;
- pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
+ pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
pdata = sensor->host_priv;
diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
index 908dfd712e8e..3e048ad65647 100644
--- a/drivers/media/platform/omap3isp/ispqueue.h
+++ b/drivers/media/platform/omap3isp/ispqueue.h
@@ -28,6 +28,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/mm_types.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/wait.h>
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 8dac17511e61..a908d006f527 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -219,7 +219,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
{
struct media_pad *remote;
- remote = media_entity_remote_source(&video->pad);
+ remote = media_entity_remote_pad(&video->pad);
if (remote == NULL ||
media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -314,7 +314,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
* entity can be found, and stop checking the pipeline if the
* source entity isn't a subdev.
*/
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (pad == NULL)
return -EPIPE;
@@ -901,7 +901,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
continue;
/* ISP entities have always sink pad == 0. Find source. */
- source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+ source_pad = media_entity_remote_pad(&ents[i]->pads[0]);
if (source_pad == NULL)
continue;
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 70438a0f62ae..40b298ab87f1 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -845,7 +845,7 @@ static int camif_pipeline_validate(struct camif_dev *camif)
int ret;
/* Retrieve format at the sensor subdev source pad */
- pad = media_entity_remote_source(&camif->pads[0]);
+ pad = media_entity_remote_pad(&camif->pads[0]);
if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
return -EPIPE;
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index 0d0fab1a7b5e..b38574702fe9 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -341,10 +341,11 @@ static void camif_clk_put(struct camif_dev *camif)
int i;
for (i = 0; i < CLK_MAX_NUM; i++) {
- if (IS_ERR_OR_NULL(camif->clock[i]))
+ if (IS_ERR(camif->clock[i]))
continue;
clk_unprepare(camif->clock[i]);
clk_put(camif->clock[i]);
+ camif->clock[i] = ERR_PTR(-EINVAL);
}
}
@@ -352,6 +353,9 @@ static int camif_clk_get(struct camif_dev *camif)
{
int ret, i;
+ for (i = 1; i < CLK_MAX_NUM; i++)
+ camif->clock[i] = ERR_PTR(-EINVAL);
+
for (i = 0; i < CLK_MAX_NUM; i++) {
camif->clock[i] = clk_get(camif->dev, camif_clocks[i]);
if (IS_ERR(camif->clock[i])) {
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
index 1a3b4fc05ec6..a9e3b16460b8 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.c
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -379,7 +379,7 @@ static void camif_hw_set_prescaler(struct camif_vp *vp)
camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg);
}
-void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
+static void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
{
struct camif_dev *camif = vp->camif;
struct camif_scaler *scaler = &vp->scaler;
@@ -426,7 +426,7 @@ void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
scaler->main_h_ratio, scaler->main_v_ratio);
}
-void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
+static void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
{
struct camif_dev *camif = vp->camif;
struct camif_scaler *scaler = &vp->scaler;
@@ -601,6 +601,6 @@ void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
pr_info("--- %s ---\n", label);
for (i = 0; i < ARRAY_SIZE(registers); i++) {
u32 cfg = readl(camif->io_base + registers[i].offset);
- printk(KERN_INFO "%s:\t0x%08x\n", registers[i].name, cfg);
+ dev_info(camif->dev, "%s:\t0x%08x\n", registers[i].name, cfg);
}
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index d12faa691af8..a130dcdb7206 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -1424,7 +1424,7 @@ static void *mfc_get_drv_data(struct platform_device *pdev)
if (pdev->dev.of_node) {
const struct of_device_id *match;
- match = of_match_node(of_match_ptr(exynos_mfc_match),
+ match = of_match_node(exynos_mfc_match,
pdev->dev.of_node);
if (match)
driver_data = (struct s5p_mfc_variant *)match->data;
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 4e86626dad4b..1b34c3629858 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -576,16 +576,22 @@ static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
return hdmi_streamoff(hdev);
}
-static void hdmi_resource_poweron(struct hdmi_resources *res)
+static int hdmi_resource_poweron(struct hdmi_resources *res)
{
+ int ret;
+
/* turn HDMI power on */
- regulator_bulk_enable(res->regul_count, res->regul_bulk);
+ ret = regulator_bulk_enable(res->regul_count, res->regul_bulk);
+ if (ret < 0)
+ return ret;
/* power-on hdmi physical interface */
clk_enable(res->hdmiphy);
/* use VPP as parent clock; HDMIPHY is not working yet */
clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
/* turn clocks on */
clk_enable(res->sclk_hdmi);
+
+ return 0;
}
static void hdmi_resource_poweroff(struct hdmi_resources *res)
@@ -728,11 +734,13 @@ static int hdmi_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- int ret = 0;
+ int ret;
dev_dbg(dev, "%s\n", __func__);
- hdmi_resource_poweron(&hdev->res);
+ ret = hdmi_resource_poweron(&hdev->res);
+ if (ret < 0)
+ return ret;
/* starting MHL */
ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
@@ -755,6 +763,15 @@ static const struct dev_pm_ops hdmi_pm_ops = {
.runtime_resume = hdmi_runtime_resume,
};
+static void hdmi_resource_clear_clocks(struct hdmi_resources *res)
+{
+ res->hdmi = ERR_PTR(-EINVAL);
+ res->sclk_hdmi = ERR_PTR(-EINVAL);
+ res->sclk_pixel = ERR_PTR(-EINVAL);
+ res->sclk_hdmiphy = ERR_PTR(-EINVAL);
+ res->hdmiphy = ERR_PTR(-EINVAL);
+}
+
static void hdmi_resources_cleanup(struct hdmi_device *hdev)
{
struct hdmi_resources *res = &hdev->res;
@@ -765,17 +782,18 @@ static void hdmi_resources_cleanup(struct hdmi_device *hdev)
regulator_bulk_free(res->regul_count, res->regul_bulk);
/* kfree is NULL-safe */
kfree(res->regul_bulk);
- if (!IS_ERR_OR_NULL(res->hdmiphy))
+ if (!IS_ERR(res->hdmiphy))
clk_put(res->hdmiphy);
- if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+ if (!IS_ERR(res->sclk_hdmiphy))
clk_put(res->sclk_hdmiphy);
- if (!IS_ERR_OR_NULL(res->sclk_pixel))
+ if (!IS_ERR(res->sclk_pixel))
clk_put(res->sclk_pixel);
- if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ if (!IS_ERR(res->sclk_hdmi))
clk_put(res->sclk_hdmi);
- if (!IS_ERR_OR_NULL(res->hdmi))
+ if (!IS_ERR(res->hdmi))
clk_put(res->hdmi);
memset(res, 0, sizeof(*res));
+ hdmi_resource_clear_clocks(res);
}
static int hdmi_resources_init(struct hdmi_device *hdev)
@@ -793,8 +811,9 @@ static int hdmi_resources_init(struct hdmi_device *hdev)
dev_dbg(dev, "HDMI resource init\n");
memset(res, 0, sizeof(*res));
- /* get clocks, power */
+ hdmi_resource_clear_clocks(res);
+ /* get clocks, power */
res->hdmi = clk_get(dev, "hdmi");
if (IS_ERR(res->hdmi)) {
dev_err(dev, "failed to get clock 'hdmi'\n");
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c
index 5733033a6ead..51805a5e2beb 100644
--- a/drivers/media/platform/s5p-tv/mixer_drv.c
+++ b/drivers/media/platform/s5p-tv/mixer_drv.c
@@ -211,6 +211,15 @@ fail:
return ret;
}
+static void mxr_resource_clear_clocks(struct mxr_resources *res)
+{
+ res->mixer = ERR_PTR(-EINVAL);
+ res->vp = ERR_PTR(-EINVAL);
+ res->sclk_mixer = ERR_PTR(-EINVAL);
+ res->sclk_hdmi = ERR_PTR(-EINVAL);
+ res->sclk_dac = ERR_PTR(-EINVAL);
+}
+
static void mxr_release_plat_resources(struct mxr_device *mdev)
{
free_irq(mdev->res.irq, mdev);
@@ -222,15 +231,15 @@ static void mxr_release_clocks(struct mxr_device *mdev)
{
struct mxr_resources *res = &mdev->res;
- if (!IS_ERR_OR_NULL(res->sclk_dac))
+ if (!IS_ERR(res->sclk_dac))
clk_put(res->sclk_dac);
- if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ if (!IS_ERR(res->sclk_hdmi))
clk_put(res->sclk_hdmi);
- if (!IS_ERR_OR_NULL(res->sclk_mixer))
+ if (!IS_ERR(res->sclk_mixer))
clk_put(res->sclk_mixer);
- if (!IS_ERR_OR_NULL(res->vp))
+ if (!IS_ERR(res->vp))
clk_put(res->vp);
- if (!IS_ERR_OR_NULL(res->mixer))
+ if (!IS_ERR(res->mixer))
clk_put(res->mixer);
}
@@ -239,6 +248,8 @@ static int mxr_acquire_clocks(struct mxr_device *mdev)
struct mxr_resources *res = &mdev->res;
struct device *dev = mdev->dev;
+ mxr_resource_clear_clocks(res);
+
res->mixer = clk_get(dev, "mixer");
if (IS_ERR(res->mixer)) {
mxr_err(mdev, "failed to get clock 'mixer'\n");
@@ -299,6 +310,7 @@ static void mxr_release_resources(struct mxr_device *mdev)
mxr_release_clocks(mdev);
mxr_release_plat_resources(mdev);
memset(&mdev->res, 0, sizeof(mdev->res));
+ mxr_resource_clear_clocks(&mdev->res);
}
static void mxr_release_layers(struct mxr_device *mdev)
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index ef0efdf422fe..641b1f071e06 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -81,8 +81,9 @@ int mxr_acquire_video(struct mxr_device *mdev,
}
mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
- if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+ if (IS_ERR(mdev->alloc_ctx)) {
mxr_err(mdev, "could not acquire vb2 allocator\n");
+ ret = PTR_ERR(mdev->alloc_ctx);
goto fail_v4l2_dev;
}
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
index ab6f9ef89423..0afa90f0f6ab 100644
--- a/drivers/media/platform/s5p-tv/sdo_drv.c
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -262,11 +262,21 @@ static int sdo_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct sdo_device *sdev = sd_to_sdev(sd);
+ int ret;
dev_info(dev, "resume\n");
- clk_enable(sdev->sclk_dac);
- regulator_enable(sdev->vdac);
- regulator_enable(sdev->vdet);
+
+ ret = clk_enable(sdev->sclk_dac);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_enable(sdev->vdac);
+ if (ret < 0)
+ goto dac_clk_dis;
+
+ ret = regulator_enable(sdev->vdet);
+ if (ret < 0)
+ goto vdac_r_dis;
/* software reset */
sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
@@ -285,6 +295,12 @@ static int sdo_runtime_resume(struct device *dev)
SDO_COMPENSATION_CVBS_COMP_OFF);
sdo_reg_debug(sdev);
return 0;
+
+vdac_r_dis:
+ regulator_disable(sdev->vdac);
+dac_clk_dis:
+ clk_disable(sdev->sclk_dac);
+ return ret;
}
static const struct dev_pm_ops sdo_pm_ops = {
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index 39b77d24b9c2..3dd762e5b67e 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -249,7 +249,9 @@ static int sii9234_runtime_resume(struct device *dev)
int ret;
dev_info(dev, "resume start\n");
- regulator_enable(ctx->power);
+ ret = regulator_enable(ctx->power);
+ if (ret < 0)
+ return ret;
ret = sii9234_reset(ctx);
if (ret)
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 59a9deefb242..aa4cca371cbf 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -359,10 +359,7 @@ static int sh_veu_context_init(struct sh_veu_dev *veu)
veu->m2m_ctx = v4l2_m2m_ctx_init(veu->m2m_dev, veu,
sh_veu_queue_init);
- if (IS_ERR(veu->m2m_ctx))
- return PTR_ERR(veu->m2m_ctx);
-
- return 0;
+ return PTR_RET(veu->m2m_ctx);
}
static int sh_veu_querycap(struct file *file, void *priv,
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 7d0235069c87..7a9c5e9329f2 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -1248,32 +1248,6 @@ static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
return res;
}
-static int sh_vou_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *id)
-{
- struct sh_vou_device *vou_dev = video_drvdata(file);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int sh_vou_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct sh_vou_device *vou_dev = video_drvdata(file);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
-}
-
-static int sh_vou_s_register(struct file *file, void *fh,
- const struct v4l2_dbg_register *reg)
-{
- struct sh_vou_device *vou_dev = video_drvdata(file);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
-}
-#endif
-
/* sh_vou display ioctl operations */
static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
.vidioc_querycap = sh_vou_querycap,
@@ -1292,11 +1266,6 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
.vidioc_cropcap = sh_vou_cropcap,
.vidioc_g_crop = sh_vou_g_crop,
.vidioc_s_crop = sh_vou_s_crop,
- .vidioc_g_chip_ident = sh_vou_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = sh_vou_g_register,
- .vidioc_s_register = sh_vou_s_register,
-#endif
};
static const struct v4l2_file_operations sh_vou_fops = {
@@ -1313,7 +1282,6 @@ static const struct video_device sh_vou_video_template = {
.fops = &sh_vou_fops,
.ioctl_ops = &sh_vou_ioctl_ops,
.tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
- .current_norm = V4L2_STD_NTSC_M,
.vfl_dir = VFL_DIR_TX,
};
@@ -1352,7 +1320,7 @@ static int sh_vou_probe(struct platform_device *pdev)
pix = &vou_dev->pix;
/* Fill in defaults */
- vou_dev->std = sh_vou_video_template.current_norm;
+ vou_dev->std = V4L2_STD_NTSC_M;
rect->left = 0;
rect->top = 0;
rect->width = VOU_MAX_IMAGE_WIDTH;
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index b139b525bb16..626dcccc37da 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -8,6 +8,9 @@ config SOC_CAMERA
over a bus like PCI or USB. For example some i2c camera connected
directly to the data bus of an SoC.
+config SOC_CAMERA_SCALE_CROP
+ tristate
+
config SOC_CAMERA_PLATFORM
tristate "platform camera support"
depends on SOC_CAMERA
@@ -27,14 +30,10 @@ config VIDEO_MX1
---help---
This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
-config MX3_VIDEO
- bool
-
config VIDEO_MX3
tristate "i.MX3x Camera Sensor Interface driver"
depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
select VIDEOBUF2_DMA_CONTIG
- select MX3_VIDEO
---help---
This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -55,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
select VIDEOBUF2_DMA_CONTIG
+ select SOC_CAMERA_SCALE_CROP
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
@@ -66,14 +66,10 @@ config VIDEO_OMAP1
---help---
This is a v4l2 driver for the TI OMAP1 camera interface
-config VIDEO_MX2_HOSTSUPPORT
- bool
-
config VIDEO_MX2
tristate "i.MX27 Camera Sensor Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && MACH_MX27
select VIDEOBUF2_DMA_CONTIG
- select VIDEO_MX2_HOSTSUPPORT
---help---
This is a v4l2 driver for the i.MX27 Camera Sensor Interface
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index 136b7f8ff10d..39186224c16a 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -1,4 +1,8 @@
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o
+obj-$(CONFIG_SOC_CAMERA_SCALE_CROP) += soc_scale_crop.o
+
+# a platform subdevice driver stub, allowing to support cameras by adding a
+# couple of callback functions to the board code
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
# soc-camera host drivers have to be linked after camera drivers
@@ -10,5 +14,3 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
-
-ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 1abbb36d0755..104485632501 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -102,7 +102,6 @@ struct atmel_isi {
struct list_head video_buffer_list;
struct frame_buffer *active;
- struct soc_camera_device *icd;
struct soc_camera_host soc_host;
};
@@ -367,7 +366,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
/* Check if already in a frame */
if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
- dev_err(isi->icd->parent, "Already in frame handling.\n");
+ dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
return;
}
@@ -746,16 +745,26 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
return formats;
}
-/* Called with .host_lock held */
static int isi_camera_add_device(struct soc_camera_device *icd)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void isi_camera_remove_device(struct soc_camera_device *icd)
+{
+ dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
+/* Called with .host_lock held */
+static int isi_camera_clock_start(struct soc_camera_host *ici)
+{
struct atmel_isi *isi = ici->priv;
int ret;
- if (isi->icd)
- return -EBUSY;
-
ret = clk_enable(isi->pclk);
if (ret)
return ret;
@@ -766,25 +775,16 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
return ret;
}
- isi->icd = icd;
- dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
- icd->devnum);
return 0;
}
+
/* Called with .host_lock held */
-static void isi_camera_remove_device(struct soc_camera_device *icd)
+static void isi_camera_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct atmel_isi *isi = ici->priv;
- BUG_ON(icd != isi->icd);
-
clk_disable(isi->mck);
clk_disable(isi->pclk);
- isi->icd = NULL;
-
- dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
- icd->devnum);
}
static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
@@ -888,6 +888,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
.owner = THIS_MODULE,
.add = isi_camera_add_device,
.remove = isi_camera_remove_device,
+ .clock_start = isi_camera_clock_start,
+ .clock_stop = isi_camera_clock_stop,
.set_fmt = isi_camera_set_fmt,
.try_fmt = isi_camera_try_fmt,
.get_formats = isi_camera_get_formats,
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index a3fd8d63546c..fea3e61476ae 100644
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
@@ -104,7 +104,6 @@ struct mx1_buffer {
*/
struct mx1_camera_dev {
struct soc_camera_host soc_host;
- struct soc_camera_device *icd;
struct mx1_camera_pdata *pdata;
struct mx1_buffer *active;
struct resource *res;
@@ -220,7 +219,7 @@ out:
static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
{
struct videobuf_buffer *vbuf = &pcdev->active->vb;
- struct device *dev = pcdev->icd->parent;
+ struct device *dev = pcdev->soc_host.icd->parent;
int ret;
if (unlikely(!pcdev->active)) {
@@ -331,7 +330,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
static void mx1_camera_dma_irq(int channel, void *data)
{
struct mx1_camera_dev *pcdev = data;
- struct device *dev = pcdev->icd->parent;
+ struct device *dev = pcdev->soc_host.icd->parent;
struct mx1_buffer *buf;
struct videobuf_buffer *vb;
unsigned long flags;
@@ -389,7 +388,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
*/
div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
- dev_dbg(pcdev->icd->parent,
+ dev_dbg(pcdev->soc_host.icd->parent,
"System clock %lukHz, target freq %dkHz, divisor %lu\n",
lcdclk / 1000, mclk / 1000, div);
@@ -400,7 +399,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
{
unsigned int csicr1 = CSICR1_EN;
- dev_dbg(pcdev->icd->parent, "Activate device\n");
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Activate device\n");
clk_prepare_enable(pcdev->clk);
@@ -416,7 +415,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
{
- dev_dbg(pcdev->icd->parent, "Deactivate device\n");
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Deactivate device\n");
/* Disable all CSI interface */
__raw_writel(0x00, pcdev->base + CSICR1);
@@ -424,36 +423,38 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
clk_disable_unprepare(pcdev->clk);
}
+static int mx1_camera_add_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void mx1_camera_remove_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
/*
* The following two functions absolutely depend on the fact, that
* there can be only one camera on i.MX1/i.MXL camera sensor interface
*/
-static int mx1_camera_add_device(struct soc_camera_device *icd)
+static int mx1_camera_clock_start(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx1_camera_dev *pcdev = ici->priv;
- if (pcdev->icd)
- return -EBUSY;
-
- dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
- icd->devnum);
-
mx1_camera_activate(pcdev);
- pcdev->icd = icd;
-
return 0;
}
-static void mx1_camera_remove_device(struct soc_camera_device *icd)
+static void mx1_camera_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx1_camera_dev *pcdev = ici->priv;
unsigned int csicr1;
- BUG_ON(icd != pcdev->icd);
-
/* disable interrupts */
csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK;
__raw_writel(csicr1, pcdev->base + CSICR1);
@@ -461,12 +462,7 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
/* Stop DMA engine */
imx_dma_disable(pcdev->dma_chan);
- dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
- icd->devnum);
-
mx1_camera_deactivate(pcdev);
-
- pcdev->icd = NULL;
}
static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
@@ -679,6 +675,8 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
.owner = THIS_MODULE,
.add = mx1_camera_add_device,
.remove = mx1_camera_remove_device,
+ .clock_start = mx1_camera_clock_start,
+ .clock_stop = mx1_camera_clock_stop,
.set_bus_param = mx1_camera_set_bus_param,
.set_fmt = mx1_camera_set_fmt,
.try_fmt = mx1_camera_try_fmt,
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 5bbeb43e4531..45a0276be4e5 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -236,7 +236,6 @@ enum mx2_camera_type {
struct mx2_camera_dev {
struct device *dev;
struct soc_camera_host soc_host;
- struct soc_camera_device *icd;
struct clk *clk_emma_ahb, *clk_emma_ipg;
struct clk *clk_csi_ahb, *clk_csi_per;
@@ -394,8 +393,8 @@ static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
writel(phys, pcdev->base_emma +
PRP_DEST_Y_PTR - 0x14 * bufnum);
if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
- u32 imgsize = pcdev->icd->user_height *
- pcdev->icd->user_width;
+ u32 imgsize = pcdev->soc_host.icd->user_height *
+ pcdev->soc_host.icd->user_width;
writel(phys + imgsize, pcdev->base_emma +
PRP_DEST_CB_PTR - 0x14 * bufnum);
@@ -413,20 +412,30 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
writel(0, pcdev->base_emma + PRP_CNTL);
}
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
/*
* The following two functions absolutely depend on the fact, that
* there can be only one camera on mx2 camera sensor interface
*/
-static int mx2_camera_add_device(struct soc_camera_device *icd)
+static int mx2_camera_clock_start(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
int ret;
u32 csicr1;
- if (pcdev->icd)
- return -EBUSY;
-
ret = clk_prepare_enable(pcdev->clk_csi_ahb);
if (ret < 0)
return ret;
@@ -441,12 +450,8 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
pcdev->csicr1 = csicr1;
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
- pcdev->icd = icd;
pcdev->frame_count = 0;
- dev_info(icd->parent, "Camera driver attached to camera %d\n",
- icd->devnum);
-
return 0;
exit_csi_ahb:
@@ -455,19 +460,11 @@ exit_csi_ahb:
return ret;
}
-static void mx2_camera_remove_device(struct soc_camera_device *icd)
+static void mx2_camera_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
- BUG_ON(icd != pcdev->icd);
-
- dev_info(icd->parent, "Camera driver detached from camera %d\n",
- icd->devnum);
-
mx2_camera_deactivate(pcdev);
-
- pcdev->icd = NULL;
}
/*
@@ -1280,6 +1277,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
.owner = THIS_MODULE,
.add = mx2_camera_add_device,
.remove = mx2_camera_remove_device,
+ .clock_start = mx2_camera_clock_start,
+ .clock_stop = mx2_camera_clock_stop,
.set_fmt = mx2_camera_set_fmt,
.set_crop = mx2_camera_set_crop,
.get_formats = mx2_camera_get_formats,
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 5da337736cd8..1047e3e8db77 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -94,7 +94,6 @@ struct mx3_camera_dev {
* Interface. If anyone ever builds hardware to enable more than one
* camera _simultaneously_, they will have to modify this driver too
*/
- struct soc_camera_device *icd;
struct clk *clk;
void __iomem *base;
@@ -461,8 +460,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q,
}
/* First part of ipu_csi_init_interface() */
-static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
- struct soc_camera_device *icd)
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam)
{
u32 conf;
long rate;
@@ -506,51 +504,49 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
clk_prepare_enable(mx3_cam->clk);
rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
- dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+ dev_dbg(mx3_cam->soc_host.v4l2_dev.dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
if (rate)
clk_set_rate(mx3_cam->clk, rate);
}
-/* Called with .host_lock held */
static int mx3_camera_add_device(struct soc_camera_device *icd)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
+ dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
+ icd->devnum);
- if (mx3_cam->icd)
- return -EBUSY;
+ return 0;
+}
- mx3_camera_activate(mx3_cam, icd);
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
+ icd->devnum);
+}
- mx3_cam->buf_total = 0;
- mx3_cam->icd = icd;
+/* Called with .host_lock held */
+static int mx3_camera_clock_start(struct soc_camera_host *ici)
+{
+ struct mx3_camera_dev *mx3_cam = ici->priv;
- dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
- icd->devnum);
+ mx3_camera_activate(mx3_cam);
+
+ mx3_cam->buf_total = 0;
return 0;
}
/* Called with .host_lock held */
-static void mx3_camera_remove_device(struct soc_camera_device *icd)
+static void mx3_camera_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
- BUG_ON(icd != mx3_cam->icd);
-
if (*ichan) {
dma_release_channel(&(*ichan)->dma_chan);
*ichan = NULL;
}
clk_disable_unprepare(mx3_cam->clk);
-
- mx3_cam->icd = NULL;
-
- dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
- icd->devnum);
}
static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -1133,6 +1129,8 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
.owner = THIS_MODULE,
.add = mx3_camera_add_device,
.remove = mx3_camera_remove_device,
+ .clock_start = mx3_camera_clock_start,
+ .clock_stop = mx3_camera_clock_stop,
.set_crop = mx3_camera_set_crop,
.set_fmt = mx3_camera_set_fmt,
.try_fmt = mx3_camera_try_fmt,
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index 9689a6e89b7f..6769193c7c7b 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -150,7 +150,6 @@ struct omap1_cam_buf {
struct omap1_cam_dev {
struct soc_camera_host soc_host;
- struct soc_camera_device *icd;
struct clk *clk;
unsigned int irq;
@@ -564,7 +563,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
{
struct omap1_cam_buf *buf = pcdev->active;
struct videobuf_buffer *vb;
- struct device *dev = pcdev->icd->parent;
+ struct device *dev = pcdev->soc_host.icd->parent;
if (WARN_ON(!buf)) {
suspend_capture(pcdev);
@@ -790,7 +789,7 @@ out:
static irqreturn_t cam_isr(int irq, void *data)
{
struct omap1_cam_dev *pcdev = data;
- struct device *dev = pcdev->icd->parent;
+ struct device *dev = pcdev->soc_host.icd->parent;
struct omap1_cam_buf *buf = pcdev->active;
u32 it_status;
unsigned long flags;
@@ -894,19 +893,29 @@ static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
CAM_WRITE(pcdev, GPIO, !reset);
}
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+ dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+ dev_dbg(icd->parent,
+ "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
/*
* The following two functions absolutely depend on the fact, that
* there can be only one camera on OMAP1 camera sensor interface
*/
-static int omap1_cam_add_device(struct soc_camera_device *icd)
+static int omap1_cam_clock_start(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct omap1_cam_dev *pcdev = ici->priv;
u32 ctrlclock;
- if (pcdev->icd)
- return -EBUSY;
-
clk_enable(pcdev->clk);
/* setup sensor clock */
@@ -941,21 +950,14 @@ static int omap1_cam_add_device(struct soc_camera_device *icd)
sensor_reset(pcdev, false);
- pcdev->icd = icd;
-
- dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
- icd->devnum);
return 0;
}
-static void omap1_cam_remove_device(struct soc_camera_device *icd)
+static void omap1_cam_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct omap1_cam_dev *pcdev = ici->priv;
u32 ctrlclock;
- BUG_ON(icd != pcdev->icd);
-
suspend_capture(pcdev);
disable_capture(pcdev);
@@ -973,11 +975,6 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
clk_disable(pcdev->clk);
-
- pcdev->icd = NULL;
-
- dev_dbg(icd->parent,
- "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
}
/* Duplicate standard formats based on host capability of byte swapping */
@@ -1535,6 +1532,8 @@ static struct soc_camera_host_ops omap1_host_ops = {
.owner = THIS_MODULE,
.add = omap1_cam_add_device,
.remove = omap1_cam_remove_device,
+ .clock_start = omap1_cam_clock_start,
+ .clock_stop = omap1_cam_clock_stop,
.get_formats = omap1_cam_get_formats,
.set_crop = omap1_cam_set_crop,
.set_fmt = omap1_cam_set_fmt,
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index d665242e8207..d4df305fcc18 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -200,7 +200,6 @@ struct pxa_camera_dev {
* interface. If anyone ever builds hardware to enable more than
* one camera, they will have to modify this driver too
*/
- struct soc_camera_device *icd;
struct clk *clk;
unsigned int irq;
@@ -956,40 +955,39 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static int pxa_camera_add_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void pxa_camera_remove_device(struct soc_camera_device *icd)
+{
+ dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
/*
* The following two functions absolutely depend on the fact, that
* there can be only one camera on PXA quick capture interface
* Called with .host_lock held
*/
-static int pxa_camera_add_device(struct soc_camera_device *icd)
+static int pxa_camera_clock_start(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct pxa_camera_dev *pcdev = ici->priv;
- if (pcdev->icd)
- return -EBUSY;
-
pxa_camera_activate(pcdev);
- pcdev->icd = icd;
-
- dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
- icd->devnum);
-
return 0;
}
/* Called with .host_lock held */
-static void pxa_camera_remove_device(struct soc_camera_device *icd)
+static void pxa_camera_clock_stop(struct soc_camera_host *ici)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct pxa_camera_dev *pcdev = ici->priv;
- BUG_ON(icd != pcdev->icd);
-
- dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
- icd->devnum);
-
/* disable capture, disable interrupts */
__raw_writel(0x3ff, pcdev->base + CICR0);
@@ -999,8 +997,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
DCSR(pcdev->dma_chans[2]) = 0;
pxa_camera_deactivate(pcdev);
-
- pcdev->icd = NULL;
}
static int test_platform_param(struct pxa_camera_dev *pcdev,
@@ -1596,8 +1592,8 @@ static int pxa_camera_suspend(struct device *dev)
pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
- if (pcdev->icd) {
- struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+ if (pcdev->soc_host.icd) {
+ struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd);
ret = v4l2_subdev_call(sd, core, s_power, 0);
if (ret == -ENOIOCTLCMD)
ret = 0;
@@ -1622,8 +1618,8 @@ static int pxa_camera_resume(struct device *dev)
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
- if (pcdev->icd) {
- struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+ if (pcdev->soc_host.icd) {
+ struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd);
ret = v4l2_subdev_call(sd, core, s_power, 1);
if (ret == -ENOIOCTLCMD)
ret = 0;
@@ -1640,6 +1636,8 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.owner = THIS_MODULE,
.add = pxa_camera_add_device,
.remove = pxa_camera_remove_device,
+ .clock_start = pxa_camera_clock_start,
+ .clock_stop = pxa_camera_clock_stop,
.set_crop = pxa_camera_set_crop,
.get_formats = pxa_camera_get_formats,
.put_formats = pxa_camera_put_formats,
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 143d29fe0137..f2de0066089a 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
+#include <linux/of.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -35,6 +36,7 @@
#include <linux/pm_runtime.h>
#include <linux/sched.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/soc_camera.h>
@@ -44,6 +46,8 @@
#include <media/v4l2-mediabus.h>
#include <media/soc_mediabus.h>
+#include "soc_scale_crop.h"
+
/* register offsets for sh7722 / sh7723 */
#define CAPSR 0x00 /* Capture start register */
@@ -95,7 +99,10 @@ struct sh_mobile_ceu_buffer {
struct sh_mobile_ceu_dev {
struct soc_camera_host ici;
- struct soc_camera_device *icd;
+ /* Asynchronous CSI2 linking */
+ struct v4l2_async_subdev *csi2_asd;
+ struct v4l2_subdev *csi2_sd;
+ /* Synchronous probing compatibility */
struct platform_device *csi2_pdev;
unsigned int irq;
@@ -119,6 +126,7 @@ struct sh_mobile_ceu_dev {
enum v4l2_field field;
int sequence;
+ unsigned long flags;
unsigned int image_mode:1;
unsigned int is_16bit:1;
@@ -163,7 +171,6 @@ static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
{
int i, success = 0;
- struct soc_camera_device *icd = pcdev->icd;
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
@@ -185,9 +192,8 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
udelay(1);
}
-
if (2 != success) {
- dev_warn(icd->pdev, "soft reset time out\n");
+ dev_warn(pcdev->ici.v4l2_dev.dev, "soft reset time out\n");
return -EIO;
}
@@ -277,7 +283,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
*/
static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
{
- struct soc_camera_device *icd = pcdev->icd;
+ struct soc_camera_device *icd = pcdev->ici.icd;
dma_addr_t phys_addr_top, phys_addr_bottom;
unsigned long top1, top2;
unsigned long bottom1, bottom2;
@@ -534,72 +540,92 @@ static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
{
struct v4l2_subdev *sd;
- if (!pcdev->csi2_pdev)
- return NULL;
+ if (pcdev->csi2_sd)
+ return pcdev->csi2_sd;
- v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
- if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd))
- return sd;
+ if (pcdev->csi2_asd) {
+ char name[] = "sh-mobile-csi2";
+ v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
+ if (!strncmp(name, sd->name, sizeof(name) - 1)) {
+ pcdev->csi2_sd = sd;
+ return sd;
+ }
+ }
return NULL;
}
-/* Called with .host_lock held */
+static struct v4l2_subdev *csi2_subdev(struct sh_mobile_ceu_dev *pcdev,
+ struct soc_camera_device *icd)
+{
+ struct v4l2_subdev *sd = pcdev->csi2_sd;
+
+ return sd && sd->grp_id == soc_camera_grp_id(icd) ? sd : NULL;
+}
+
static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- struct v4l2_subdev *csi2_sd;
+ struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
int ret;
- if (pcdev->icd)
- return -EBUSY;
-
- dev_info(icd->parent,
- "SuperH Mobile CEU driver attached to camera %d\n",
- icd->devnum);
-
- pm_runtime_get_sync(ici->v4l2_dev.dev);
-
- pcdev->buf_total = 0;
-
- ret = sh_mobile_ceu_soft_reset(pcdev);
-
- csi2_sd = find_csi2(pcdev);
if (csi2_sd) {
csi2_sd->grp_id = soc_camera_grp_id(icd);
v4l2_set_subdev_hostdata(csi2_sd, icd);
}
ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
- pm_runtime_put(ici->v4l2_dev.dev);
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
return ret;
- }
/*
* -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver
* has not found this soc-camera device among its clients
*/
- if (ret == -ENODEV && csi2_sd)
+ if (csi2_sd && ret == -ENODEV)
csi2_sd->grp_id = 0;
- pcdev->icd = icd;
+
+ dev_info(icd->parent,
+ "SuperH Mobile CEU%s driver attached to camera %d\n",
+ csi2_sd && csi2_sd->grp_id ? "/CSI-2" : "", icd->devnum);
return 0;
}
-/* Called with .host_lock held */
static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
- BUG_ON(icd != pcdev->icd);
+ dev_info(icd->parent,
+ "SuperH Mobile CEU driver detached from camera %d\n",
+ icd->devnum);
v4l2_subdev_call(csi2_sd, core, s_power, 0);
- if (csi2_sd)
- csi2_sd->grp_id = 0;
+}
+
+/* Called with .host_lock held */
+static int sh_mobile_ceu_clock_start(struct soc_camera_host *ici)
+{
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ int ret;
+
+ pm_runtime_get_sync(ici->v4l2_dev.dev);
+
+ pcdev->buf_total = 0;
+
+ ret = sh_mobile_ceu_soft_reset(pcdev);
+
+ return 0;
+}
+
+/* Called with .host_lock held */
+static void sh_mobile_ceu_clock_stop(struct soc_camera_host *ici)
+{
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
/* disable capture, disable interrupts */
ceu_write(pcdev, CEIER, 0);
sh_mobile_ceu_soft_reset(pcdev);
@@ -614,12 +640,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
spin_unlock_irq(&pcdev->lock);
pm_runtime_put(ici->v4l2_dev.dev);
-
- dev_info(icd->parent,
- "SuperH Mobile CEU driver detached from camera %d\n",
- icd->devnum);
-
- pcdev->icd = NULL;
}
/*
@@ -705,7 +725,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
}
/* CSI2 special configuration */
- if (pcdev->pdata->csi2) {
+ if (csi2_subdev(pcdev, icd)) {
in_width = ((in_width - 2) * 2);
left_offset *= 2;
}
@@ -762,13 +782,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
struct soc_camera_device *icd)
{
- if (pcdev->csi2_pdev) {
- struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
- if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd))
- return csi2_sd;
- }
-
- return soc_camera_to_subdev(icd);
+ return csi2_subdev(pcdev, icd) ? : soc_camera_to_subdev(icd);
}
#define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \
@@ -809,7 +823,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
/* Make choises, based on platform preferences */
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW)
+ if (pcdev->flags & SH_CEU_FLAG_HSYNC_LOW)
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
@@ -817,7 +831,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW)
+ if (pcdev->flags & SH_CEU_FLAG_VSYNC_LOW)
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
@@ -872,11 +886,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
- if (pcdev->pdata->csi2) /* CSI2 mode */
+ if (csi2_subdev(pcdev, icd)) /* CSI2 mode */
value |= 3 << 12;
else if (pcdev->is_16bit)
value |= 1 << 12;
- else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT)
+ else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT)
value |= 2 << 12;
ceu_write(pcdev, CAMCR, value);
@@ -993,8 +1007,6 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
-static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
-
static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl)
{
return container_of(ctrl->handler, struct soc_camera_device,
@@ -1051,7 +1063,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
return 0;
}
- if (!pcdev->pdata->csi2) {
+ if (!csi2_subdev(pcdev, icd)) {
/* Are there any restrictions in the CSI-2 case? */
ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
if (ret < 0)
@@ -1072,7 +1084,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
/* FIXME: subwindow is lost between close / open */
/* Cache current client geometry */
- ret = client_g_rect(sd, &rect);
+ ret = soc_camera_client_g_rect(sd, &rect);
if (ret < 0)
return ret;
@@ -1182,334 +1194,8 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
icd->host_priv = NULL;
}
-/* Check if any dimension of r1 is smaller than respective one of r2 */
-static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
- return r1->width < r2->width || r1->height < r2->height;
-}
-
-/* Check if r1 fails to cover r2 */
-static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
- return r1->left > r2->left || r1->top > r2->top ||
- r1->left + r1->width < r2->left + r2->width ||
- r1->top + r1->height < r2->top + r2->height;
-}
-
-static unsigned int scale_down(unsigned int size, unsigned int scale)
-{
- return (size * 4096 + scale / 2) / scale;
-}
-
-static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
-{
- return (input * 4096 + output / 2) / output;
-}
-
-/* Get and store current client crop */
-static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
-{
- struct v4l2_crop crop;
- struct v4l2_cropcap cap;
- int ret;
-
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, g_crop, &crop);
- if (!ret) {
- *rect = crop.c;
- return ret;
- }
-
- /* Camera driver doesn't support .g_crop(), assume default rectangle */
- cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
- if (!ret)
- *rect = cap.defrect;
-
- return ret;
-}
-
-/* Client crop has changed, update our sub-rectangle to remain within the area */
-static void update_subrect(struct sh_mobile_ceu_cam *cam)
-{
- struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect;
-
- if (rect->width < subrect->width)
- subrect->width = rect->width;
-
- if (rect->height < subrect->height)
- subrect->height = rect->height;
-
- if (rect->left > subrect->left)
- subrect->left = rect->left;
- else if (rect->left + rect->width >
- subrect->left + subrect->width)
- subrect->left = rect->left + rect->width -
- subrect->width;
-
- if (rect->top > subrect->top)
- subrect->top = rect->top;
- else if (rect->top + rect->height >
- subrect->top + subrect->height)
- subrect->top = rect->top + rect->height -
- subrect->height;
-}
-
-/*
- * The common for both scaling and cropping iterative approach is:
- * 1. try if the client can produce exactly what requested by the user
- * 2. if (1) failed, try to double the client image until we get one big enough
- * 3. if (2) failed, try to request the maximum image
- */
-static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
- struct v4l2_crop *cam_crop)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
- struct device *dev = sd->v4l2_dev->dev;
- struct sh_mobile_ceu_cam *cam = icd->host_priv;
- struct v4l2_cropcap cap;
- int ret;
- unsigned int width, height;
-
- v4l2_subdev_call(sd, video, s_crop, crop);
- ret = client_g_rect(sd, cam_rect);
- if (ret < 0)
- return ret;
-
- /*
- * Now cam_crop contains the current camera input rectangle, and it must
- * be within camera cropcap bounds
- */
- if (!memcmp(rect, cam_rect, sizeof(*rect))) {
- /* Even if camera S_CROP failed, but camera rectangle matches */
- dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
- rect->width, rect->height, rect->left, rect->top);
- cam->rect = *cam_rect;
- return 0;
- }
-
- /* Try to fix cropping, that camera hasn't managed to set */
- dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
- cam_rect->width, cam_rect->height,
- cam_rect->left, cam_rect->top,
- rect->width, rect->height, rect->left, rect->top);
-
- /* We need sensor maximum rectangle */
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
- if (ret < 0)
- return ret;
-
- /* Put user requested rectangle within sensor bounds */
- soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
- cap.bounds.width);
- soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
- cap.bounds.height);
-
- /*
- * Popular special case - some cameras can only handle fixed sizes like
- * QVGA, VGA,... Take care to avoid infinite loop.
- */
- width = max(cam_rect->width, 2);
- height = max(cam_rect->height, 2);
-
- /*
- * Loop as long as sensor is not covering the requested rectangle and
- * is still within its bounds
- */
- while (!ret && (is_smaller(cam_rect, rect) ||
- is_inside(cam_rect, rect)) &&
- (cap.bounds.width > width || cap.bounds.height > height)) {
-
- width *= 2;
- height *= 2;
-
- cam_rect->width = width;
- cam_rect->height = height;
-
- /*
- * We do not know what capabilities the camera has to set up
- * left and top borders. We could try to be smarter in iterating
- * them, e.g., if camera current left is to the right of the
- * target left, set it to the middle point between the current
- * left and minimum left. But that would add too much
- * complexity: we would have to iterate each border separately.
- * Instead we just drop to the left and top bounds.
- */
- if (cam_rect->left > rect->left)
- cam_rect->left = cap.bounds.left;
-
- if (cam_rect->left + cam_rect->width < rect->left + rect->width)
- cam_rect->width = rect->left + rect->width -
- cam_rect->left;
-
- if (cam_rect->top > rect->top)
- cam_rect->top = cap.bounds.top;
-
- if (cam_rect->top + cam_rect->height < rect->top + rect->height)
- cam_rect->height = rect->top + rect->height -
- cam_rect->top;
-
- v4l2_subdev_call(sd, video, s_crop, cam_crop);
- ret = client_g_rect(sd, cam_rect);
- dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
- cam_rect->width, cam_rect->height,
- cam_rect->left, cam_rect->top);
- }
-
- /* S_CROP must not modify the rectangle */
- if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
- /*
- * The camera failed to configure a suitable cropping,
- * we cannot use the current rectangle, set to max
- */
- *cam_rect = cap.bounds;
- v4l2_subdev_call(sd, video, s_crop, cam_crop);
- ret = client_g_rect(sd, cam_rect);
- dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
- cam_rect->width, cam_rect->height,
- cam_rect->left, cam_rect->top);
- }
-
- if (!ret) {
- cam->rect = *cam_rect;
- update_subrect(cam);
- }
-
- return ret;
-}
-
-/* Iterative s_mbus_fmt, also updates cached client crop on success */
-static int client_s_fmt(struct soc_camera_device *icd,
- struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct sh_mobile_ceu_dev *pcdev = ici->priv;
- struct sh_mobile_ceu_cam *cam = icd->host_priv;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct device *dev = icd->parent;
- unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
- unsigned int max_width, max_height;
- struct v4l2_cropcap cap;
- bool ceu_1to1;
- int ret;
-
- ret = v4l2_device_call_until_err(sd->v4l2_dev,
- soc_camera_grp_id(icd), video,
- s_mbus_fmt, mf);
- if (ret < 0)
- return ret;
-
- dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
-
- if (width == mf->width && height == mf->height) {
- /* Perfect! The client has done it all. */
- ceu_1to1 = true;
- goto update_cache;
- }
-
- ceu_1to1 = false;
- if (!ceu_can_scale)
- goto update_cache;
-
- cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, cropcap, &cap);
- if (ret < 0)
- return ret;
-
- max_width = min(cap.bounds.width, pcdev->max_width);
- max_height = min(cap.bounds.height, pcdev->max_height);
-
- /* Camera set a format, but geometry is not precise, try to improve */
- tmp_w = mf->width;
- tmp_h = mf->height;
-
- /* width <= max_width && height <= max_height - guaranteed by try_fmt */
- while ((width > tmp_w || height > tmp_h) &&
- tmp_w < max_width && tmp_h < max_height) {
- tmp_w = min(2 * tmp_w, max_width);
- tmp_h = min(2 * tmp_h, max_height);
- mf->width = tmp_w;
- mf->height = tmp_h;
- ret = v4l2_device_call_until_err(sd->v4l2_dev,
- soc_camera_grp_id(icd), video,
- s_mbus_fmt, mf);
- dev_geo(dev, "Camera scaled to %ux%u\n",
- mf->width, mf->height);
- if (ret < 0) {
- /* This shouldn't happen */
- dev_err(dev, "Client failed to set format: %d\n", ret);
- return ret;
- }
- }
-
-update_cache:
- /* Update cache */
- ret = client_g_rect(sd, &cam->rect);
- if (ret < 0)
- return ret;
-
- if (ceu_1to1)
- cam->subrect = cam->rect;
- else
- update_subrect(cam);
-
- return 0;
-}
-
-/**
- * @width - on output: user width, mapped back to input
- * @height - on output: user height, mapped back to input
- * @mf - in- / output camera output window
- */
-static int client_scale(struct soc_camera_device *icd,
- struct v4l2_mbus_framefmt *mf,
- unsigned int *width, unsigned int *height,
- bool ceu_can_scale)
-{
- struct sh_mobile_ceu_cam *cam = icd->host_priv;
- struct device *dev = icd->parent;
- struct v4l2_mbus_framefmt mf_tmp = *mf;
- unsigned int scale_h, scale_v;
- int ret;
-
- /*
- * 5. Apply iterative camera S_FMT for camera user window (also updates
- * client crop cache and the imaginary sub-rectangle).
- */
- ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale);
- if (ret < 0)
- return ret;
-
- dev_geo(dev, "5: camera scaled to %ux%u\n",
- mf_tmp.width, mf_tmp.height);
-
- /* 6. Retrieve camera output window (g_fmt) */
-
- /* unneeded - it is already in "mf_tmp" */
-
- /* 7. Calculate new client scales. */
- scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width);
- scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height);
-
- mf->width = mf_tmp.width;
- mf->height = mf_tmp.height;
- mf->colorspace = mf_tmp.colorspace;
-
- /*
- * 8. Calculate new CEU crop - apply camera scales to previously
- * updated "effective" crop.
- */
- *width = scale_down(cam->subrect.width, scale_h);
- *height = scale_down(cam->subrect.height, scale_v);
-
- dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
-
- return 0;
-}
+#define scale_down(size, scale) soc_camera_shift_scale(size, 12, scale)
+#define calc_generic_scale(in, out) soc_camera_calc_scale(in, 12, out)
/*
* CEU can scale and crop, but we don't want to waste bandwidth and kill the
@@ -1547,7 +1233,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
* 1. - 2. Apply iterative camera S_CROP for new input window, read back
* actual camera rectangle.
*/
- ret = client_s_crop(icd, &a_writable, &cam_crop);
+ ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+ &cam->rect, &cam->subrect);
if (ret < 0)
return ret;
@@ -1666,55 +1353,6 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
return 0;
}
-/*
- * Calculate real client output window by applying new scales to the current
- * client crop. New scales are calculated from the requested output format and
- * CEU crop, mapped backed onto the client input (subrect).
- */
-static void calculate_client_output(struct soc_camera_device *icd,
- const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
-{
- struct sh_mobile_ceu_cam *cam = icd->host_priv;
- struct device *dev = icd->parent;
- struct v4l2_rect *cam_subrect = &cam->subrect;
- unsigned int scale_v, scale_h;
-
- if (cam_subrect->width == cam->rect.width &&
- cam_subrect->height == cam->rect.height) {
- /* No sub-cropping */
- mf->width = pix->width;
- mf->height = pix->height;
- return;
- }
-
- /* 1.-2. Current camera scales and subwin - cached. */
-
- dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
- cam_subrect->width, cam_subrect->height,
- cam_subrect->left, cam_subrect->top);
-
- /*
- * 3. Calculate new combined scales from input sub-window to requested
- * user window.
- */
-
- /*
- * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
- * (128x96) or larger than VGA
- */
- scale_h = calc_generic_scale(cam_subrect->width, pix->width);
- scale_v = calc_generic_scale(cam_subrect->height, pix->height);
-
- dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
-
- /*
- * 4. Calculate desired client output window by applying combined scales
- * to client (real) input window.
- */
- mf->width = scale_down(cam->rect.width, scale_h);
- mf->height = scale_down(cam->rect.height, scale_v);
-}
-
/* Similar to set_crop multistage iterative algorithm */
static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
@@ -1727,8 +1365,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct v4l2_mbus_framefmt mf;
__u32 pixfmt = pix->pixelformat;
const struct soc_camera_format_xlate *xlate;
- /* Keep Compiler Happy */
- unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
+ unsigned int ceu_sub_width = pcdev->max_width,
+ ceu_sub_height = pcdev->max_height;
u16 scale_v, scale_h;
int ret;
bool image_mode;
@@ -1755,7 +1393,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
}
/* 1.-4. Calculate desired client output geometry */
- calculate_client_output(icd, pix, &mf);
+ soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, 12);
mf.field = pix->field;
mf.colorspace = pix->colorspace;
mf.code = xlate->code;
@@ -1777,8 +1415,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
/* 5. - 9. */
- ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height,
- image_mode && V4L2_FIELD_NONE == field);
+ ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect,
+ &mf, &ceu_sub_width, &ceu_sub_height,
+ image_mode && V4L2_FIELD_NONE == field, 12);
dev_geo(dev, "5-9: client scale return %d\n", ret);
@@ -2036,6 +1675,8 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.owner = THIS_MODULE,
.add = sh_mobile_ceu_add_device,
.remove = sh_mobile_ceu_remove_device,
+ .clock_start = sh_mobile_ceu_clock_start,
+ .clock_stop = sh_mobile_ceu_clock_stop,
.get_formats = sh_mobile_ceu_get_formats,
.put_formats = sh_mobile_ceu_put_formats,
.get_crop = sh_mobile_ceu_get_crop,
@@ -2079,7 +1720,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
struct resource *res;
void __iomem *base;
unsigned int irq;
- int err = 0;
+ int err, i;
struct bus_wait wait = {
.completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
.notifier.notifier_call = bus_notify,
@@ -2104,13 +1745,36 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
init_completion(&pcdev->complete);
pcdev->pdata = pdev->dev.platform_data;
- if (!pcdev->pdata) {
+ if (!pcdev->pdata && !pdev->dev.of_node) {
dev_err(&pdev->dev, "CEU platform data not set.\n");
return -EINVAL;
}
- pcdev->max_width = pcdev->pdata->max_width ? : 2560;
- pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+ /* TODO: implement per-device bus flags */
+ if (pcdev->pdata) {
+ pcdev->max_width = pcdev->pdata->max_width;
+ pcdev->max_height = pcdev->pdata->max_height;
+ pcdev->flags = pcdev->pdata->flags;
+ }
+
+ if (!pcdev->max_width) {
+ unsigned int v;
+ err = of_property_read_u32(pdev->dev.of_node, "renesas,max-width", &v);
+ if (!err)
+ pcdev->max_width = v;
+
+ if (!pcdev->max_width)
+ pcdev->max_width = 2560;
+ }
+ if (!pcdev->max_height) {
+ unsigned int v;
+ err = of_property_read_u32(pdev->dev.of_node, "renesas,max-height", &v);
+ if (!err)
+ pcdev->max_height = v;
+
+ if (!pcdev->max_height)
+ pcdev->max_height = 1920;
+ }
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
@@ -2160,31 +1824,60 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
goto exit_free_clk;
}
- err = soc_camera_host_register(&pcdev->ici);
- if (err)
- goto exit_free_ctx;
+ if (pcdev->pdata && pcdev->pdata->asd_sizes) {
+ struct v4l2_async_subdev **asd;
+ char name[] = "sh-mobile-csi2";
+ int j;
+
+ /*
+ * CSI2 interfacing: several groups can use CSI2, pick up the
+ * first one
+ */
+ asd = pcdev->pdata->asd;
+ for (j = 0; pcdev->pdata->asd_sizes[j]; j++) {
+ for (i = 0; i < pcdev->pdata->asd_sizes[j]; i++, asd++) {
+ dev_dbg(&pdev->dev, "%s(): subdev #%d, type %u\n",
+ __func__, i, (*asd)->bus_type);
+ if ((*asd)->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
+ !strncmp(name, (*asd)->match.platform.name,
+ sizeof(name) - 1)) {
+ pcdev->csi2_asd = *asd;
+ break;
+ }
+ }
+ if (pcdev->csi2_asd)
+ break;
+ }
- /* CSI2 interfacing */
- csi2 = pcdev->pdata->csi2;
+ pcdev->ici.asd = pcdev->pdata->asd;
+ pcdev->ici.asd_sizes = pcdev->pdata->asd_sizes;
+ }
+
+ /* Legacy CSI2 interfacing */
+ csi2 = pcdev->pdata ? pcdev->pdata->csi2 : NULL;
if (csi2) {
+ /*
+ * TODO: remove this once all users are converted to
+ * asynchronous CSI2 probing. If it has to be kept, csi2
+ * platform device resources have to be added, using
+ * platform_device_add_resources()
+ */
struct platform_device *csi2_pdev =
platform_device_alloc("sh-mobile-csi2", csi2->id);
struct sh_csi2_pdata *csi2_pdata = csi2->platform_data;
if (!csi2_pdev) {
err = -ENOMEM;
- goto exit_host_unregister;
+ goto exit_free_ctx;
}
pcdev->csi2_pdev = csi2_pdev;
- err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata));
+ err = platform_device_add_data(csi2_pdev, csi2_pdata,
+ sizeof(*csi2_pdata));
if (err < 0)
goto exit_pdev_put;
- csi2_pdata = csi2_pdev->dev.platform_data;
- csi2_pdata->v4l2_dev = &pcdev->ici.v4l2_dev;
-
csi2_pdev->resource = csi2->resource;
csi2_pdev->num_resources = csi2->num_resources;
@@ -2226,17 +1919,38 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
err = -ENODEV;
goto exit_pdev_unregister;
}
+
+ pcdev->csi2_sd = platform_get_drvdata(csi2_pdev);
+ }
+
+ err = soc_camera_host_register(&pcdev->ici);
+ if (err)
+ goto exit_csi2_unregister;
+
+ if (csi2) {
+ err = v4l2_device_register_subdev(&pcdev->ici.v4l2_dev,
+ pcdev->csi2_sd);
+ dev_dbg(&pdev->dev, "%s(): ret(register_subdev) = %d\n",
+ __func__, err);
+ if (err < 0)
+ goto exit_host_unregister;
+ /* v4l2_device_register_subdev() took a reference too */
+ module_put(pcdev->csi2_sd->owner);
}
return 0;
-exit_pdev_unregister:
- platform_device_del(pcdev->csi2_pdev);
-exit_pdev_put:
- pcdev->csi2_pdev->resource = NULL;
- platform_device_put(pcdev->csi2_pdev);
exit_host_unregister:
soc_camera_host_unregister(&pcdev->ici);
+exit_csi2_unregister:
+ if (csi2) {
+ module_put(pcdev->csi2_pdev->dev.driver->owner);
+exit_pdev_unregister:
+ platform_device_del(pcdev->csi2_pdev);
+exit_pdev_put:
+ pcdev->csi2_pdev->resource = NULL;
+ platform_device_put(pcdev->csi2_pdev);
+ }
exit_free_ctx:
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
exit_free_clk:
@@ -2287,10 +2001,18 @@ static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = {
.runtime_resume = sh_mobile_ceu_runtime_nop,
};
+static const struct of_device_id sh_mobile_ceu_of_match[] = {
+ { .compatible = "renesas,sh-mobile-ceu" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_ceu_of_match);
+
static struct platform_driver sh_mobile_ceu_driver = {
.driver = {
.name = "sh_mobile_ceu",
+ .owner = THIS_MODULE,
.pm = &sh_mobile_ceu_dev_pm_ops,
+ .of_match_table = sh_mobile_ceu_of_match,
},
.probe = sh_mobile_ceu_probe,
.remove = sh_mobile_ceu_remove,
@@ -2314,5 +2036,5 @@ module_exit(sh_mobile_ceu_exit);
MODULE_DESCRIPTION("SuperH Mobile CEU driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.6");
+MODULE_VERSION("0.1.0");
MODULE_ALIAS("platform:sh_mobile_ceu");
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index 09cb4fc88f34..05dd21a35d63 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -36,7 +36,6 @@
struct sh_csi2 {
struct v4l2_subdev subdev;
- struct list_head list;
unsigned int irq;
unsigned long mipi_flags;
void __iomem *base;
@@ -44,6 +43,8 @@ struct sh_csi2 {
struct sh_csi2_client_config *client;
};
+static void sh_csi2_hwinit(struct sh_csi2 *priv);
+
static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
@@ -132,10 +133,58 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
+ struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+
+ if (!priv->mipi_flags) {
+ struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
+ struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+ unsigned long common_flags, csi2_flags;
+ struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,};
+ int ret;
+
+ /* Check if we can support this camera */
+ csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
+ V4L2_MBUS_CSI2_1_LANE;
+
+ switch (pdata->type) {
+ case SH_CSI2C:
+ if (priv->client->lanes != 1)
+ csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+ break;
+ case SH_CSI2I:
+ switch (priv->client->lanes) {
+ default:
+ csi2_flags |= V4L2_MBUS_CSI2_4_LANE;
+ case 3:
+ csi2_flags |= V4L2_MBUS_CSI2_3_LANE;
+ case 2:
+ csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+ }
+ }
+
+ ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &client_cfg);
+ if (ret == -ENOIOCTLCMD)
+ common_flags = csi2_flags;
+ else if (!ret)
+ common_flags = soc_mbus_config_compatible(&client_cfg,
+ csi2_flags);
+ else
+ common_flags = 0;
+
+ if (!common_flags)
+ return -EINVAL;
+
+ /* All good: camera MIPI configuration supported */
+ priv->mipi_flags = common_flags;
+ }
+
+ if (cfg) {
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ }
return 0;
}
@@ -146,8 +195,17 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd,
struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
- struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,
- .flags = priv->mipi_flags};
+ struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,};
+ int ret = sh_csi2_g_mbus_config(sd, NULL);
+
+ if (ret < 0)
+ return ret;
+
+ pm_runtime_get_sync(&priv->pdev->dev);
+
+ sh_csi2_hwinit(priv);
+
+ client_cfg.flags = priv->mipi_flags;
return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg);
}
@@ -202,19 +260,19 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv)
static int sh_csi2_client_connect(struct sh_csi2 *priv)
{
- struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
- struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev);
- struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
struct device *dev = v4l2_get_subdevdata(&priv->subdev);
- struct v4l2_mbus_config cfg;
- unsigned long common_flags, csi2_flags;
- int i, ret;
+ struct sh_csi2_pdata *pdata = dev->platform_data;
+ struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev);
+ int i;
if (priv->client)
return -EBUSY;
for (i = 0; i < pdata->num_clients; i++)
- if (&pdata->clients[i].pdev->dev == icd->pdev)
+ if ((pdata->clients[i].pdev &&
+ &pdata->clients[i].pdev->dev == icd->pdev) ||
+ (icd->control &&
+ strcmp(pdata->clients[i].name, dev_name(icd->control))))
break;
dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i);
@@ -222,46 +280,8 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv)
if (i == pdata->num_clients)
return -ENODEV;
- /* Check if we can support this camera */
- csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE;
-
- switch (pdata->type) {
- case SH_CSI2C:
- if (pdata->clients[i].lanes != 1)
- csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
- break;
- case SH_CSI2I:
- switch (pdata->clients[i].lanes) {
- default:
- csi2_flags |= V4L2_MBUS_CSI2_4_LANE;
- case 3:
- csi2_flags |= V4L2_MBUS_CSI2_3_LANE;
- case 2:
- csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
- }
- }
-
- cfg.type = V4L2_MBUS_CSI2;
- ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg);
- if (ret == -ENOIOCTLCMD)
- common_flags = csi2_flags;
- else if (!ret)
- common_flags = soc_mbus_config_compatible(&cfg,
- csi2_flags);
- else
- common_flags = 0;
-
- if (!common_flags)
- return -EINVAL;
-
- /* All good: camera MIPI configuration supported */
- priv->mipi_flags = common_flags;
priv->client = pdata->clients + i;
- pm_runtime_get_sync(dev);
-
- sh_csi2_hwinit(priv);
-
return 0;
}
@@ -304,11 +324,18 @@ static int sh_csi2_probe(struct platform_device *pdev)
/* Platform data specify the PHY, lanes, ECC, CRC */
struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* Interrupt unused so far */
irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0 || !pdata) {
+ if (!res || (int)irq <= 0) {
dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
return -ENODEV;
}
@@ -319,10 +346,6 @@ static int sh_csi2_probe(struct platform_device *pdev)
return -EINVAL;
}
- priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
priv->irq = irq;
priv->base = devm_ioremap_resource(&pdev->dev, res);
@@ -330,37 +353,35 @@ static int sh_csi2_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
priv->pdev = pdev;
- platform_set_drvdata(pdev, priv);
+ priv->subdev.owner = THIS_MODULE;
+ priv->subdev.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &priv->subdev);
v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
- dev_name(pdata->v4l2_dev->dev));
- ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev);
- dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+ dev_name(&pdev->dev));
+
+ ret = v4l2_async_register_subdev(&priv->subdev);
if (ret < 0)
- goto esdreg;
+ return ret;
pm_runtime_enable(&pdev->dev);
dev_dbg(&pdev->dev, "CSI2 probed.\n");
return 0;
-
-esdreg:
- platform_set_drvdata(pdev, NULL);
-
- return ret;
}
static int sh_csi2_remove(struct platform_device *pdev)
{
- struct sh_csi2 *priv = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+ struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev);
- v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_device_unregister_subdev(subdev);
pm_runtime_disable(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 3a4efbdc7668..2dd0e5272941 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -21,21 +21,23 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/pm_runtime.h>
#include <linux/vmalloc.h>
#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-dev.h>
#include <media/videobuf-core.h>
#include <media/videobuf2-core.h>
-#include <media/soc_mediabus.h>
/* Default to VGA resolution */
#define DEFAULT_WIDTH 640
@@ -46,17 +48,39 @@
(icd)->vb_vidq.streaming : \
vb2_is_streaming(&(icd)->vb2_vidq))
+#define MAP_MAX_NUM 32
+static DECLARE_BITMAP(device_map, MAP_MAX_NUM);
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
+/*
+ * Protects lists and bitmaps of hosts and devices.
+ * Lock nesting: Ok to take ->host_lock under list_lock.
+ */
+static DEFINE_MUTEX(list_lock);
+
+struct soc_camera_async_client {
+ struct v4l2_async_subdev *sensor;
+ struct v4l2_async_notifier notifier;
+ struct platform_device *pdev;
+ struct list_head list; /* needed for clean up */
+};
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
-int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+ struct v4l2_clk *clk)
{
- int ret = regulator_bulk_enable(ssdd->num_regulators,
+ int ret = clk ? v4l2_clk_enable(clk) : 0;
+ if (ret < 0) {
+ dev_err(dev, "Cannot enable clock: %d\n", ret);
+ return ret;
+ }
+ ret = regulator_bulk_enable(ssdd->num_regulators,
ssdd->regulators);
if (ret < 0) {
dev_err(dev, "Cannot enable regulators\n");
- return ret;
+ goto eregenable;
}
if (ssdd->power) {
@@ -64,16 +88,25 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
if (ret < 0) {
dev_err(dev,
"Platform failed to power-on the camera.\n");
- regulator_bulk_disable(ssdd->num_regulators,
- ssdd->regulators);
+ goto epwron;
}
}
+ return 0;
+
+epwron:
+ regulator_bulk_disable(ssdd->num_regulators,
+ ssdd->regulators);
+eregenable:
+ if (clk)
+ v4l2_clk_disable(clk);
+
return ret;
}
EXPORT_SYMBOL(soc_camera_power_on);
-int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+ struct v4l2_clk *clk)
{
int ret = 0;
int err;
@@ -94,10 +127,21 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd
ret = ret ? : err;
}
+ if (clk)
+ v4l2_clk_disable(clk);
+
return ret;
}
EXPORT_SYMBOL(soc_camera_power_off);
+int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+{
+
+ return devm_regulator_bulk_get(dev, ssdd->num_regulators,
+ ssdd->regulators);
+}
+EXPORT_SYMBOL(soc_camera_power_init);
+
static int __soc_camera_power_on(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -235,7 +279,6 @@ static int soc_camera_enum_input(struct file *file, void *priv,
/* default is camera */
inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_UNKNOWN;
strcpy(inp->name, "Camera");
return 0;
@@ -505,6 +548,58 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
return ici->ops->set_bus_param(icd);
}
+static int soc_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ int ret;
+
+ if (ici->icd)
+ return -EBUSY;
+
+ if (!icd->clk) {
+ mutex_lock(&ici->clk_lock);
+ ret = ici->ops->clock_start(ici);
+ mutex_unlock(&ici->clk_lock);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ici->ops->add) {
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ goto eadd;
+ }
+
+ ici->icd = icd;
+
+ return 0;
+
+eadd:
+ if (!icd->clk) {
+ mutex_lock(&ici->clk_lock);
+ ici->ops->clock_stop(ici);
+ mutex_unlock(&ici->clk_lock);
+ }
+ return ret;
+}
+
+static void soc_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ if (WARN_ON(icd != ici->icd))
+ return;
+
+ if (ici->ops->remove)
+ ici->ops->remove(icd);
+ if (!icd->clk) {
+ mutex_lock(&ici->clk_lock);
+ ici->ops->clock_stop(ici);
+ mutex_unlock(&ici->clk_lock);
+ }
+ ici->icd = NULL;
+}
+
static int soc_camera_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
@@ -525,7 +620,7 @@ static int soc_camera_open(struct file *file)
return -ENODEV;
}
- icd = dev_get_drvdata(vdev->parent);
+ icd = video_get_drvdata(vdev);
ici = to_soc_camera_host(icd->parent);
ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
@@ -568,7 +663,7 @@ static int soc_camera_open(struct file *file)
if (sdesc->subdev_desc.reset)
sdesc->subdev_desc.reset(icd->pdev);
- ret = ici->ops->add(icd);
+ ret = soc_camera_add_device(icd);
if (ret < 0) {
dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
goto eiciadd;
@@ -610,8 +705,8 @@ static int soc_camera_open(struct file *file)
return 0;
/*
- * First four errors are entered with the .host_lock held
- * and use_count == 1
+ * All errors are entered with the .host_lock held, first four also
+ * with use_count == 1
*/
einitvb:
esfmt:
@@ -619,7 +714,7 @@ esfmt:
eresume:
__soc_camera_power_off(icd);
epower:
- ici->ops->remove(icd);
+ soc_camera_remove_device(icd);
eiciadd:
icd->use_count--;
mutex_unlock(&ici->host_lock);
@@ -645,7 +740,7 @@ static int soc_camera_close(struct file *file)
vb2_queue_release(&icd->vb2_vidq);
__soc_camera_power_off(icd);
- ici->ops->remove(icd);
+ soc_camera_remove_device(icd);
}
if (icd->streamer == file)
@@ -1036,76 +1131,225 @@ static int soc_camera_s_parm(struct file *file, void *fh,
return -ENOIOCTLCMD;
}
-static int soc_camera_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *id)
+static int soc_camera_probe(struct soc_camera_host *ici,
+ struct soc_camera_device *icd);
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_device *icd;
+
+ mutex_lock(&list_lock);
+
+ list_for_each_entry(icd, &devices, list)
+ if (icd->iface == ici->nr) {
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+ struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
+
+ /* The camera could have been already on, try to reset */
+ if (ssdd->reset)
+ ssdd->reset(icd->pdev);
- return v4l2_subdev_call(sd, core, g_chip_ident, id);
+ icd->parent = ici->v4l2_dev.dev;
+
+ /* Ignore errors */
+ soc_camera_probe(ici, icd);
+ }
+
+ mutex_unlock(&list_lock);
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int soc_camera_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+/*
+ * It is invalid to call v4l2_clk_enable() after a successful probing
+ * asynchronously outside of V4L2 operations, i.e. with .host_lock not held.
+ */
+static int soc_camera_clk_enable(struct v4l2_clk *clk)
{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_device *icd = clk->priv;
+ struct soc_camera_host *ici;
+ int ret;
+
+ if (!icd || !icd->parent)
+ return -ENODEV;
+
+ ici = to_soc_camera_host(icd->parent);
+
+ if (!try_module_get(ici->ops->owner))
+ return -ENODEV;
- return v4l2_subdev_call(sd, core, g_register, reg);
+ /*
+ * If a different client is currently being probed, the host will tell
+ * you to go
+ */
+ mutex_lock(&ici->clk_lock);
+ ret = ici->ops->clock_start(ici);
+ mutex_unlock(&ici->clk_lock);
+ return ret;
}
-static int soc_camera_s_register(struct file *file, void *fh,
- const struct v4l2_dbg_register *reg)
+static void soc_camera_clk_disable(struct v4l2_clk *clk)
{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_device *icd = clk->priv;
+ struct soc_camera_host *ici;
+
+ if (!icd || !icd->parent)
+ return;
+
+ ici = to_soc_camera_host(icd->parent);
+
+ mutex_lock(&ici->clk_lock);
+ ici->ops->clock_stop(ici);
+ mutex_unlock(&ici->clk_lock);
- return v4l2_subdev_call(sd, core, s_register, reg);
+ module_put(ici->ops->owner);
}
-#endif
-static int soc_camera_probe(struct soc_camera_device *icd);
+/*
+ * Eventually, it would be more logical to make the respective host the clock
+ * owner, but then we would have to copy this struct for each ici. Besides, it
+ * would introduce the circular dependency problem, unless we port all client
+ * drivers to release the clock, when not in use.
+ */
+static const struct v4l2_clk_ops soc_camera_clk_ops = {
+ .owner = THIS_MODULE,
+ .enable = soc_camera_clk_enable,
+ .disable = soc_camera_clk_disable,
+};
-/* So far this function cannot fail */
-static void scan_add_host(struct soc_camera_host *ici)
+static int soc_camera_dyn_pdev(struct soc_camera_desc *sdesc,
+ struct soc_camera_async_client *sasc)
{
- struct soc_camera_device *icd;
+ struct platform_device *pdev;
+ int ret, i;
mutex_lock(&list_lock);
+ i = find_first_zero_bit(device_map, MAP_MAX_NUM);
+ if (i < MAP_MAX_NUM)
+ set_bit(i, device_map);
+ mutex_unlock(&list_lock);
+ if (i >= MAP_MAX_NUM)
+ return -ENOMEM;
- list_for_each_entry(icd, &devices, list) {
- if (icd->iface == ici->nr) {
- icd->parent = ici->v4l2_dev.dev;
- soc_camera_probe(icd);
- }
+ pdev = platform_device_alloc("soc-camera-pdrv", i);
+ if (!pdev)
+ return -ENOMEM;
+
+ ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc));
+ if (ret < 0) {
+ platform_device_put(pdev);
+ return ret;
}
- mutex_unlock(&list_lock);
+ sasc->pdev = pdev;
+
+ return 0;
+}
+
+static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_client *sasc)
+{
+ struct platform_device *pdev = sasc->pdev;
+ int ret;
+
+ ret = platform_device_add(pdev);
+ if (ret < 0 || !pdev->dev.driver)
+ return NULL;
+
+ return platform_get_drvdata(pdev);
+}
+
+/* Locking: called with .host_lock held */
+static int soc_camera_probe_finish(struct soc_camera_device *icd)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ sd->grp_id = soc_camera_grp_id(icd);
+ v4l2_set_subdev_hostdata(sd, icd);
+
+ ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = soc_camera_add_device(icd);
+ if (ret < 0) {
+ dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
+ return ret;
+ }
+
+ /* At this point client .probe() should have run already */
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eusrfmt;
+
+ icd->field = V4L2_FIELD_ANY;
+
+ ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ goto evidstart;
+
+ /* Try to improve our guess of a reasonable window format */
+ if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+ icd->colorspace = mf.colorspace;
+ icd->field = mf.field;
+ }
+ soc_camera_remove_device(icd);
+
+ return 0;
+
+evidstart:
+ soc_camera_free_user_formats(icd);
+eusrfmt:
+ soc_camera_remove_device(icd);
+
+ return ret;
}
#ifdef CONFIG_I2C_BOARDINFO
-static int soc_camera_init_i2c(struct soc_camera_device *icd,
+static int soc_camera_i2c_init(struct soc_camera_device *icd,
struct soc_camera_desc *sdesc)
{
struct i2c_client *client;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct soc_camera_host *ici;
struct soc_camera_host_desc *shd = &sdesc->host_desc;
- struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
+ struct i2c_adapter *adap;
struct v4l2_subdev *subdev;
+ char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ int ret;
+ /* First find out how we link the main client */
+ if (icd->sasc) {
+ /* Async non-OF probing handled by the subdevice list */
+ return -EPROBE_DEFER;
+ }
+
+ ici = to_soc_camera_host(icd->parent);
+ adap = i2c_get_adapter(shd->i2c_adapter_id);
if (!adap) {
dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
shd->i2c_adapter_id);
- goto ei2cga;
+ return -ENODEV;
}
shd->board_info->platform_data = &sdesc->subdev_desc;
+ snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+ shd->i2c_adapter_id, shd->board_info->addr);
+
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ if (IS_ERR(icd->clk)) {
+ ret = PTR_ERR(icd->clk);
+ goto eclkreg;
+ }
+
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
shd->board_info, NULL);
- if (!subdev)
+ if (!subdev) {
+ ret = -ENODEV;
goto ei2cnd;
+ }
client = v4l2_get_subdevdata(subdev);
@@ -1114,39 +1358,203 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
return 0;
ei2cnd:
+ v4l2_clk_unregister(icd->clk);
+eclkreg:
+ icd->clk = NULL;
i2c_put_adapter(adap);
-ei2cga:
- return -ENODEV;
+ return ret;
}
-static void soc_camera_free_i2c(struct soc_camera_device *icd)
+static void soc_camera_i2c_free(struct soc_camera_device *icd)
{
struct i2c_client *client =
to_i2c_client(to_soc_camera_control(icd));
- struct i2c_adapter *adap = client->adapter;
+ struct i2c_adapter *adap;
icd->control = NULL;
+ if (icd->sasc)
+ return;
+
+ adap = client->adapter;
v4l2_device_unregister_subdev(i2c_get_clientdata(client));
i2c_unregister_device(client);
i2c_put_adapter(adap);
+ v4l2_clk_unregister(icd->clk);
+ icd->clk = NULL;
+}
+
+/*
+ * V4L2 asynchronous notifier callbacks. They are all called under a v4l2-async
+ * internal global mutex, therefore cannot race against other asynchronous
+ * events. Until notifier->complete() (soc_camera_async_complete()) is called,
+ * the video device node is not registered and no V4L fops can occur. Unloading
+ * of the host driver also calls a v4l2-async function, so also there we're
+ * protected.
+ */
+static int soc_camera_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct soc_camera_async_client *sasc = container_of(notifier,
+ struct soc_camera_async_client, notifier);
+ struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+ if (asd == sasc->sensor && !WARN_ON(icd->control)) {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /*
+ * Only now we get subdevice-specific information like
+ * regulators, flags, callbacks, etc.
+ */
+ if (client) {
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+ struct soc_camera_subdev_desc *ssdd =
+ soc_camera_i2c_to_desc(client);
+ if (ssdd) {
+ memcpy(&sdesc->subdev_desc, ssdd,
+ sizeof(sdesc->subdev_desc));
+ if (ssdd->reset)
+ ssdd->reset(icd->pdev);
+ }
+
+ icd->control = &client->dev;
+ }
+ }
+
+ return 0;
+}
+
+static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct soc_camera_async_client *sasc = container_of(notifier,
+ struct soc_camera_async_client, notifier);
+ struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+ if (icd->clk) {
+ v4l2_clk_unregister(icd->clk);
+ icd->clk = NULL;
+ }
+}
+
+static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)
+{
+ struct soc_camera_async_client *sasc = container_of(notifier,
+ struct soc_camera_async_client, notifier);
+ struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+ if (to_soc_camera_control(icd)) {
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ int ret;
+
+ mutex_lock(&list_lock);
+ ret = soc_camera_probe(ici, icd);
+ mutex_unlock(&list_lock);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scan_async_group(struct soc_camera_host *ici,
+ struct v4l2_async_subdev **asd, unsigned int size)
+{
+ struct soc_camera_async_subdev *sasd;
+ struct soc_camera_async_client *sasc;
+ struct soc_camera_device *icd;
+ struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
+ char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ int ret, i;
+
+ /* First look for a sensor */
+ for (i = 0; i < size; i++) {
+ sasd = container_of(asd[i], struct soc_camera_async_subdev, asd);
+ if (sasd->role == SOCAM_SUBDEV_DATA_SOURCE)
+ break;
+ }
+
+ if (i == size || asd[i]->bus_type != V4L2_ASYNC_BUS_I2C) {
+ /* All useless */
+ dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n");
+ return -ENODEV;
+ }
+
+ /* Or shall this be managed by the soc-camera device? */
+ sasc = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasc), GFP_KERNEL);
+ if (!sasc)
+ return -ENOMEM;
+
+ /* HACK: just need a != NULL */
+ sdesc.host_desc.board_info = ERR_PTR(-ENODATA);
+
+ ret = soc_camera_dyn_pdev(&sdesc, sasc);
+ if (ret < 0)
+ return ret;
+
+ sasc->sensor = &sasd->asd;
+
+ icd = soc_camera_add_pdev(sasc);
+ if (!icd) {
+ platform_device_put(sasc->pdev);
+ return -ENOMEM;
+ }
+
+ sasc->notifier.subdev = asd;
+ sasc->notifier.num_subdevs = size;
+ sasc->notifier.bound = soc_camera_async_bound;
+ sasc->notifier.unbind = soc_camera_async_unbind;
+ sasc->notifier.complete = soc_camera_async_complete;
+
+ icd->sasc = sasc;
+ icd->parent = ici->v4l2_dev.dev;
+
+ snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+ sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
+
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ if (IS_ERR(icd->clk)) {
+ ret = PTR_ERR(icd->clk);
+ goto eclkreg;
+ }
+
+ ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
+ if (!ret)
+ return 0;
+
+ v4l2_clk_unregister(icd->clk);
+eclkreg:
+ icd->clk = NULL;
+ platform_device_unregister(sasc->pdev);
+ dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
+
+ return ret;
+}
+
+static void scan_async_host(struct soc_camera_host *ici)
+{
+ struct v4l2_async_subdev **asd;
+ int j;
+
+ for (j = 0, asd = ici->asd; ici->asd_sizes[j]; j++) {
+ scan_async_group(ici, asd, ici->asd_sizes[j]);
+ asd += ici->asd_sizes[j];
+ }
}
#else
-#define soc_camera_init_i2c(icd, sdesc) (-ENODEV)
-#define soc_camera_free_i2c(icd) do {} while (0)
+#define soc_camera_i2c_init(icd, sdesc) (-ENODEV)
+#define soc_camera_i2c_free(icd) do {} while (0)
+#define scan_async_host(ici) do {} while (0)
#endif
-static int soc_camera_video_start(struct soc_camera_device *icd);
-static int video_dev_create(struct soc_camera_device *icd);
/* Called during host-driver probe */
-static int soc_camera_probe(struct soc_camera_device *icd)
+static int soc_camera_probe(struct soc_camera_host *ici,
+ struct soc_camera_device *icd)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
struct soc_camera_host_desc *shd = &sdesc->host_desc;
- struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct device *control = NULL;
- struct v4l2_subdev *sd;
- struct v4l2_mbus_framefmt mf;
int ret;
dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
@@ -1162,30 +1570,32 @@ static int soc_camera_probe(struct soc_camera_device *icd)
if (ret < 0)
return ret;
- /* The camera could have been already on, try to reset */
- if (ssdd->reset)
- ssdd->reset(icd->pdev);
-
- mutex_lock(&ici->host_lock);
- ret = ici->ops->add(icd);
- mutex_unlock(&ici->host_lock);
- if (ret < 0)
- goto eadd;
-
/* Must have icd->vdev before registering the device */
ret = video_dev_create(icd);
if (ret < 0)
goto evdc;
+ /*
+ * ..._video_start() will create a device node, video_register_device()
+ * itself is protected against concurrent open() calls, but we also have
+ * to protect our data also during client probing.
+ */
+
/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
if (shd->board_info) {
- ret = soc_camera_init_i2c(icd, sdesc);
- if (ret < 0)
- goto eadddev;
+ ret = soc_camera_i2c_init(icd, sdesc);
+ if (ret < 0 && ret != -EPROBE_DEFER)
+ goto eadd;
} else if (!shd->add_device || !shd->del_device) {
ret = -EINVAL;
- goto eadddev;
+ goto eadd;
} else {
+ mutex_lock(&ici->clk_lock);
+ ret = ici->ops->clock_start(ici);
+ mutex_unlock(&ici->clk_lock);
+ if (ret < 0)
+ goto eadd;
+
if (shd->module_name)
ret = request_module(shd->module_name);
@@ -1206,81 +1616,49 @@ static int soc_camera_probe(struct soc_camera_device *icd)
}
}
- sd = soc_camera_to_subdev(icd);
- sd->grp_id = soc_camera_grp_id(icd);
- v4l2_set_subdev_hostdata(sd, icd);
-
- ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
- if (ret < 0)
- goto ectrl;
-
- /* At this point client .probe() should have run already */
- ret = soc_camera_init_user_formats(icd);
- if (ret < 0)
- goto eiufmt;
-
- icd->field = V4L2_FIELD_ANY;
-
- /*
- * ..._video_start() will create a device node, video_register_device()
- * itself is protected against concurrent open() calls, but we also have
- * to protect our data.
- */
mutex_lock(&ici->host_lock);
-
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- goto evidstart;
-
- /* Try to improve our guess of a reasonable window format */
- if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
- icd->user_width = mf.width;
- icd->user_height = mf.height;
- icd->colorspace = mf.colorspace;
- icd->field = mf.field;
- }
-
- ici->ops->remove(icd);
-
+ ret = soc_camera_probe_finish(icd);
mutex_unlock(&ici->host_lock);
+ if (ret < 0)
+ goto efinish;
return 0;
-evidstart:
- mutex_unlock(&ici->host_lock);
- soc_camera_free_user_formats(icd);
-eiufmt:
-ectrl:
+efinish:
if (shd->board_info) {
- soc_camera_free_i2c(icd);
+ soc_camera_i2c_free(icd);
} else {
shd->del_device(icd);
module_put(control->driver->owner);
- }
enodrv:
eadddev:
+ mutex_lock(&ici->clk_lock);
+ ici->ops->clock_stop(ici);
+ mutex_unlock(&ici->clk_lock);
+ }
+eadd:
video_device_release(icd->vdev);
icd->vdev = NULL;
+ if (icd->vdev) {
+ video_device_release(icd->vdev);
+ icd->vdev = NULL;
+ }
evdc:
- mutex_lock(&ici->host_lock);
- ici->ops->remove(icd);
- mutex_unlock(&ici->host_lock);
-eadd:
v4l2_ctrl_handler_free(&icd->ctrl_handler);
return ret;
}
/*
* This is called on device_unregister, which only means we have to disconnect
- * from the host, but not remove ourselves from the device list
+ * from the host, but not remove ourselves from the device list. With
+ * asynchronous client probing this can also be called without
+ * soc_camera_probe_finish() having run. Careful with clean up.
*/
static int soc_camera_remove(struct soc_camera_device *icd)
{
struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
struct video_device *vdev = icd->vdev;
- BUG_ON(!icd->parent);
-
v4l2_ctrl_handler_free(&icd->ctrl_handler);
if (vdev) {
video_unregister_device(vdev);
@@ -1288,15 +1666,27 @@ static int soc_camera_remove(struct soc_camera_device *icd)
}
if (sdesc->host_desc.board_info) {
- soc_camera_free_i2c(icd);
+ soc_camera_i2c_free(icd);
} else {
- struct device_driver *drv = to_soc_camera_control(icd)->driver;
+ struct device *dev = to_soc_camera_control(icd);
+ struct device_driver *drv = dev ? dev->driver : NULL;
if (drv) {
sdesc->host_desc.del_device(icd);
module_put(drv->owner);
}
}
- soc_camera_free_user_formats(icd);
+
+ if (icd->num_user_formats)
+ soc_camera_free_user_formats(icd);
+
+ if (icd->clk) {
+ /* For the synchronous case */
+ v4l2_clk_unregister(icd->clk);
+ icd->clk = NULL;
+ }
+
+ if (icd->sasc)
+ platform_device_unregister(icd->sasc->pdev);
return 0;
}
@@ -1372,8 +1762,8 @@ int soc_camera_host_register(struct soc_camera_host *ici)
((!ici->ops->init_videobuf ||
!ici->ops->reqbufs) &&
!ici->ops->init_videobuf2) ||
- !ici->ops->add ||
- !ici->ops->remove ||
+ !ici->ops->clock_start ||
+ !ici->ops->clock_stop ||
!ici->ops->poll ||
!ici->v4l2_dev.dev)
return -EINVAL;
@@ -1407,7 +1797,18 @@ int soc_camera_host_register(struct soc_camera_host *ici)
mutex_unlock(&list_lock);
mutex_init(&ici->host_lock);
- scan_add_host(ici);
+ mutex_init(&ici->clk_lock);
+
+ if (ici->asd_sizes)
+ /*
+ * No OF, host with a list of subdevices. Don't try to mix
+ * modes by initialising some groups statically and some
+ * dynamically!
+ */
+ scan_async_host(ici);
+ else
+ /* Legacy: static platform devices from board data */
+ scan_add_host(ici);
return 0;
@@ -1420,13 +1821,30 @@ EXPORT_SYMBOL(soc_camera_host_register);
/* Unregister all clients! */
void soc_camera_host_unregister(struct soc_camera_host *ici)
{
- struct soc_camera_device *icd;
+ struct soc_camera_device *icd, *tmp;
+ struct soc_camera_async_client *sasc;
+ LIST_HEAD(notifiers);
mutex_lock(&list_lock);
-
list_del(&ici->list);
list_for_each_entry(icd, &devices, list)
- if (icd->iface == ici->nr && to_soc_camera_control(icd))
+ if (icd->iface == ici->nr && icd->sasc) {
+ /* as long as we hold the device, sasc won't be freed */
+ get_device(icd->pdev);
+ list_add(&icd->sasc->list, &notifiers);
+ }
+ mutex_unlock(&list_lock);
+
+ list_for_each_entry(sasc, &notifiers, list) {
+ /* Must call unlocked to avoid AB-BA dead-lock */
+ v4l2_async_notifier_unregister(&sasc->notifier);
+ put_device(&sasc->pdev->dev);
+ }
+
+ mutex_lock(&list_lock);
+
+ list_for_each_entry_safe(icd, tmp, &devices, list)
+ if (icd->iface == ici->nr)
soc_camera_remove(icd);
mutex_unlock(&list_lock);
@@ -1441,6 +1859,7 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
struct soc_camera_device *ix;
int num = -1, i;
+ mutex_lock(&list_lock);
for (i = 0; i < 256 && num < 0; i++) {
num = i;
/* Check if this index is available on this interface */
@@ -1452,18 +1871,34 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
}
}
- if (num < 0)
+ if (num < 0) {
/*
* ok, we have 256 cameras on this host...
* man, stay reasonable...
*/
+ mutex_unlock(&list_lock);
return -ENOMEM;
+ }
icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
+ /*
+ * Dynamically allocated devices set the bit earlier, but it doesn't hurt setting
+ * it again
+ */
+ i = to_platform_device(icd->pdev)->id;
+ if (i < 0)
+ /* One static (legacy) soc-camera platform device */
+ i = 0;
+ if (i >= MAP_MAX_NUM) {
+ mutex_unlock(&list_lock);
+ return -EBUSY;
+ }
+ set_bit(i, device_map);
list_add_tail(&icd->list, &devices);
+ mutex_unlock(&list_lock);
return 0;
}
@@ -1495,11 +1930,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_s_selection = soc_camera_s_selection,
.vidioc_g_parm = soc_camera_g_parm,
.vidioc_s_parm = soc_camera_s_parm,
- .vidioc_g_chip_ident = soc_camera_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = soc_camera_g_register,
- .vidioc_s_register = soc_camera_s_register,
-#endif
};
static int video_dev_create(struct soc_camera_device *icd)
@@ -1512,12 +1942,10 @@ static int video_dev_create(struct soc_camera_device *icd)
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
- vdev->parent = icd->pdev;
- vdev->current_norm = V4L2_STD_UNKNOWN;
+ vdev->v4l2_dev = &ici->v4l2_dev;
vdev->fops = &soc_camera_fops;
vdev->ioctl_ops = &soc_camera_ioctl_ops;
vdev->release = video_device_release;
- vdev->tvnorms = V4L2_STD_UNKNOWN;
vdev->ctrl_handler = &icd->ctrl_handler;
vdev->lock = &ici->host_lock;
@@ -1537,6 +1965,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
if (!icd->parent)
return -ENODEV;
+ video_set_drvdata(icd->vdev, icd);
ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
@@ -1563,6 +1992,12 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
if (!icd)
return -ENOMEM;
+ /*
+ * In the asynchronous case ssdd->num_regulators == 0 yet, so, the below
+ * regulator allocation is a dummy. They will be really requested later
+ * in soc_camera_async_bind(). Also note, that in that case regulators
+ * are attached to the I2C device and not to the camera platform device.
+ */
ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators,
ssdd->regulators);
if (ret < 0)
@@ -1587,11 +2022,25 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
static int soc_camera_pdrv_remove(struct platform_device *pdev)
{
struct soc_camera_device *icd = platform_get_drvdata(pdev);
+ int i;
if (!icd)
return -EINVAL;
- list_del(&icd->list);
+ i = pdev->id;
+ if (i < 0)
+ i = 0;
+
+ /*
+ * In synchronous mode with static platform devices this is called in a
+ * loop from drivers/base/dd.c::driver_detach(), no parallel execution,
+ * no need to lock. In asynchronous case the caller -
+ * soc_camera_host_unregister() - already holds the lock
+ */
+ if (test_bit(i, device_map)) {
+ clear_bit(i, device_map);
+ list_del(&icd->list);
+ }
return 0;
}
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index 1b7a88ca195b..ceaddfb85e49 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -54,7 +54,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
- return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, on);
+ return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on);
}
static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
@@ -137,7 +137,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
struct soc_camera_platform_priv *priv;
struct soc_camera_platform_info *p = pdev->dev.platform_data;
struct soc_camera_device *icd;
- int ret;
if (!p)
return -EINVAL;
@@ -165,15 +164,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
v4l2_set_subdevdata(&priv->subdev, p);
strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
- ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
- if (ret)
- goto evdrs;
-
- return ret;
-
-evdrs:
- platform_set_drvdata(pdev, NULL);
- return ret;
+ return v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
}
static int soc_camera_platform_remove(struct platform_device *pdev)
@@ -183,7 +174,6 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
p->icd->control = NULL;
v4l2_device_unregister_subdev(&priv->subdev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
new file mode 100644
index 000000000000..cbd3a34f4f3f
--- /dev/null
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -0,0 +1,402 @@
+/*
+ * soc-camera generic scaling-cropping manipulation functions
+ *
+ * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+
+#include "soc_scale_crop.h"
+
+#ifdef DEBUG_GEOMETRY
+#define dev_geo dev_info
+#else
+#define dev_geo dev_dbg
+#endif
+
+/* Check if any dimension of r1 is smaller than respective one of r2 */
+static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+ return r1->width < r2->width || r1->height < r2->height;
+}
+
+/* Check if r1 fails to cover r2 */
+static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+ return r1->left > r2->left || r1->top > r2->top ||
+ r1->left + r1->width < r2->left + r2->width ||
+ r1->top + r1->height < r2->top + r2->height;
+}
+
+/* Get and store current client crop */
+int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
+{
+ struct v4l2_crop crop;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+ if (!ret) {
+ *rect = crop.c;
+ return ret;
+ }
+
+ /* Camera driver doesn't support .g_crop(), assume default rectangle */
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (!ret)
+ *rect = cap.defrect;
+
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_client_g_rect);
+
+/* Client crop has changed, update our sub-rectangle to remain within the area */
+static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect)
+{
+ if (rect->width < subrect->width)
+ subrect->width = rect->width;
+
+ if (rect->height < subrect->height)
+ subrect->height = rect->height;
+
+ if (rect->left > subrect->left)
+ subrect->left = rect->left;
+ else if (rect->left + rect->width >
+ subrect->left + subrect->width)
+ subrect->left = rect->left + rect->width -
+ subrect->width;
+
+ if (rect->top > subrect->top)
+ subrect->top = rect->top;
+ else if (rect->top + rect->height >
+ subrect->top + subrect->height)
+ subrect->top = rect->top + rect->height -
+ subrect->height;
+}
+
+/*
+ * The common for both scaling and cropping iterative approach is:
+ * 1. try if the client can produce exactly what requested by the user
+ * 2. if (1) failed, try to double the client image until we get one big enough
+ * 3. if (2) failed, try to request the maximum image
+ */
+int soc_camera_client_s_crop(struct v4l2_subdev *sd,
+ struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+ struct v4l2_rect *target_rect, struct v4l2_rect *subrect)
+{
+ struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+ struct device *dev = sd->v4l2_dev->dev;
+ struct v4l2_cropcap cap;
+ int ret;
+ unsigned int width, height;
+
+ v4l2_subdev_call(sd, video, s_crop, crop);
+ ret = soc_camera_client_g_rect(sd, cam_rect);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now cam_crop contains the current camera input rectangle, and it must
+ * be within camera cropcap bounds
+ */
+ if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+ /* Even if camera S_CROP failed, but camera rectangle matches */
+ dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+ rect->width, rect->height, rect->left, rect->top);
+ *target_rect = *cam_rect;
+ return 0;
+ }
+
+ /* Try to fix cropping, that camera hasn't managed to set */
+ dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top,
+ rect->width, rect->height, rect->left, rect->top);
+
+ /* We need sensor maximum rectangle */
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ /* Put user requested rectangle within sensor bounds */
+ soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+ cap.bounds.width);
+ soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+ cap.bounds.height);
+
+ /*
+ * Popular special case - some cameras can only handle fixed sizes like
+ * QVGA, VGA,... Take care to avoid infinite loop.
+ */
+ width = max(cam_rect->width, 2);
+ height = max(cam_rect->height, 2);
+
+ /*
+ * Loop as long as sensor is not covering the requested rectangle and
+ * is still within its bounds
+ */
+ while (!ret && (is_smaller(cam_rect, rect) ||
+ is_inside(cam_rect, rect)) &&
+ (cap.bounds.width > width || cap.bounds.height > height)) {
+
+ width *= 2;
+ height *= 2;
+
+ cam_rect->width = width;
+ cam_rect->height = height;
+
+ /*
+ * We do not know what capabilities the camera has to set up
+ * left and top borders. We could try to be smarter in iterating
+ * them, e.g., if camera current left is to the right of the
+ * target left, set it to the middle point between the current
+ * left and minimum left. But that would add too much
+ * complexity: we would have to iterate each border separately.
+ * Instead we just drop to the left and top bounds.
+ */
+ if (cam_rect->left > rect->left)
+ cam_rect->left = cap.bounds.left;
+
+ if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+ cam_rect->width = rect->left + rect->width -
+ cam_rect->left;
+
+ if (cam_rect->top > rect->top)
+ cam_rect->top = cap.bounds.top;
+
+ if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+ cam_rect->height = rect->top + rect->height -
+ cam_rect->top;
+
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = soc_camera_client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ /* S_CROP must not modify the rectangle */
+ if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
+ /*
+ * The camera failed to configure a suitable cropping,
+ * we cannot use the current rectangle, set to max
+ */
+ *cam_rect = cap.bounds;
+ v4l2_subdev_call(sd, video, s_crop, cam_crop);
+ ret = soc_camera_client_g_rect(sd, cam_rect);
+ dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+ cam_rect->width, cam_rect->height,
+ cam_rect->left, cam_rect->top);
+ }
+
+ if (!ret) {
+ *target_rect = *cam_rect;
+ update_subrect(target_rect, subrect);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_client_s_crop);
+
+/* Iterative s_mbus_fmt, also updates cached client crop on success */
+static int client_s_fmt(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, struct v4l2_rect *subrect,
+ unsigned int max_width, unsigned int max_height,
+ struct v4l2_mbus_framefmt *mf, bool host_can_scale)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->parent;
+ unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
+ struct v4l2_cropcap cap;
+ bool host_1to1;
+ int ret;
+
+ ret = v4l2_device_call_until_err(sd->v4l2_dev,
+ soc_camera_grp_id(icd), video,
+ s_mbus_fmt, mf);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+ if (width == mf->width && height == mf->height) {
+ /* Perfect! The client has done it all. */
+ host_1to1 = true;
+ goto update_cache;
+ }
+
+ host_1to1 = false;
+ if (!host_can_scale)
+ goto update_cache;
+
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+ if (ret < 0)
+ return ret;
+
+ if (max_width > cap.bounds.width)
+ max_width = cap.bounds.width;
+ if (max_height > cap.bounds.height)
+ max_height = cap.bounds.height;
+
+ /* Camera set a format, but geometry is not precise, try to improve */
+ tmp_w = mf->width;
+ tmp_h = mf->height;
+
+ /* width <= max_width && height <= max_height - guaranteed by try_fmt */
+ while ((width > tmp_w || height > tmp_h) &&
+ tmp_w < max_width && tmp_h < max_height) {
+ tmp_w = min(2 * tmp_w, max_width);
+ tmp_h = min(2 * tmp_h, max_height);
+ mf->width = tmp_w;
+ mf->height = tmp_h;
+ ret = v4l2_device_call_until_err(sd->v4l2_dev,
+ soc_camera_grp_id(icd), video,
+ s_mbus_fmt, mf);
+ dev_geo(dev, "Camera scaled to %ux%u\n",
+ mf->width, mf->height);
+ if (ret < 0) {
+ /* This shouldn't happen */
+ dev_err(dev, "Client failed to set format: %d\n", ret);
+ return ret;
+ }
+ }
+
+update_cache:
+ /* Update cache */
+ ret = soc_camera_client_g_rect(sd, rect);
+ if (ret < 0)
+ return ret;
+
+ if (host_1to1)
+ *subrect = *rect;
+ else
+ update_subrect(rect, subrect);
+
+ return 0;
+}
+
+/**
+ * @icd - soc-camera device
+ * @rect - camera cropping window
+ * @subrect - part of rect, sent to the user
+ * @mf - in- / output camera output window
+ * @width - on input: max host input width
+ * on output: user width, mapped back to input
+ * @height - on input: max host input height
+ * on output: user height, mapped back to input
+ * @host_can_scale - host can scale this pixel format
+ * @shift - shift, used for scaling
+ */
+int soc_camera_client_scale(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, struct v4l2_rect *subrect,
+ struct v4l2_mbus_framefmt *mf,
+ unsigned int *width, unsigned int *height,
+ bool host_can_scale, unsigned int shift)
+{
+ struct device *dev = icd->parent;
+ struct v4l2_mbus_framefmt mf_tmp = *mf;
+ unsigned int scale_h, scale_v;
+ int ret;
+
+ /*
+ * 5. Apply iterative camera S_FMT for camera user window (also updates
+ * client crop cache and the imaginary sub-rectangle).
+ */
+ ret = client_s_fmt(icd, rect, subrect, *width, *height,
+ &mf_tmp, host_can_scale);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "5: camera scaled to %ux%u\n",
+ mf_tmp.width, mf_tmp.height);
+
+ /* 6. Retrieve camera output window (g_fmt) */
+
+ /* unneeded - it is already in "mf_tmp" */
+
+ /* 7. Calculate new client scales. */
+ scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width);
+ scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height);
+
+ mf->width = mf_tmp.width;
+ mf->height = mf_tmp.height;
+ mf->colorspace = mf_tmp.colorspace;
+
+ /*
+ * 8. Calculate new host crop - apply camera scales to previously
+ * updated "effective" crop.
+ */
+ *width = soc_camera_shift_scale(subrect->width, shift, scale_h);
+ *height = soc_camera_shift_scale(subrect->height, shift, scale_v);
+
+ dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
+
+ return 0;
+}
+EXPORT_SYMBOL(soc_camera_client_scale);
+
+/*
+ * Calculate real client output window by applying new scales to the current
+ * client crop. New scales are calculated from the requested output format and
+ * host crop, mapped backed onto the client input (subrect).
+ */
+void soc_camera_calc_client_output(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, struct v4l2_rect *subrect,
+ const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf,
+ unsigned int shift)
+{
+ struct device *dev = icd->parent;
+ unsigned int scale_v, scale_h;
+
+ if (subrect->width == rect->width &&
+ subrect->height == rect->height) {
+ /* No sub-cropping */
+ mf->width = pix->width;
+ mf->height = pix->height;
+ return;
+ }
+
+ /* 1.-2. Current camera scales and subwin - cached. */
+
+ dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+ subrect->width, subrect->height,
+ subrect->left, subrect->top);
+
+ /*
+ * 3. Calculate new combined scales from input sub-window to requested
+ * user window.
+ */
+
+ /*
+ * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
+ * (128x96) or larger than VGA. This and similar limitations have to be
+ * taken into account here.
+ */
+ scale_h = soc_camera_calc_scale(subrect->width, shift, pix->width);
+ scale_v = soc_camera_calc_scale(subrect->height, shift, pix->height);
+
+ dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+ /*
+ * 4. Calculate desired client output window by applying combined scales
+ * to client (real) input window.
+ */
+ mf->width = soc_camera_shift_scale(rect->width, shift, scale_h);
+ mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
+}
+EXPORT_SYMBOL(soc_camera_calc_client_output);
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.h b/drivers/media/platform/soc_camera/soc_scale_crop.h
new file mode 100644
index 000000000000..184a30dff541
--- /dev/null
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.h
@@ -0,0 +1,47 @@
+/*
+ * soc-camera generic scaling-cropping manipulation functions
+ *
+ * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.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.
+ */
+
+#ifndef SOC_SCALE_CROP_H
+#define SOC_SCALE_CROP_H
+
+#include <linux/kernel.h>
+
+struct soc_camera_device;
+
+struct v4l2_crop;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+struct v4l2_rect;
+struct v4l2_subdev;
+
+static inline unsigned int soc_camera_shift_scale(unsigned int size,
+ unsigned int shift, unsigned int scale)
+{
+ return DIV_ROUND_CLOSEST(size << shift, scale);
+}
+
+#define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out)
+
+int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
+int soc_camera_client_s_crop(struct v4l2_subdev *sd,
+ struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+ struct v4l2_rect *target_rect, struct v4l2_rect *subrect);
+int soc_camera_client_scale(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, struct v4l2_rect *subrect,
+ struct v4l2_mbus_framefmt *mf,
+ unsigned int *width, unsigned int *height,
+ bool host_can_scale, unsigned int shift);
+void soc_camera_calc_client_output(struct soc_camera_device *icd,
+ struct v4l2_rect *rect, struct v4l2_rect *subrect,
+ const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf,
+ unsigned int shift);
+
+#endif
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index a2f7bdd5104f..b557caf5b1a4 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -239,13 +239,12 @@ static int timblogiw_querycap(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
- memset(cap, 0, sizeof(*cap));
strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
- strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
- cap->version = TIMBLOGIW_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vdev->name);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -834,11 +833,9 @@ static int timblogiw_probe(struct platform_device *pdev)
goto err_request;
}
-
return 0;
err_request:
- platform_set_drvdata(pdev, NULL);
v4l2_device_unregister(&lw->v4l2_dev);
err_register:
kfree(lw);
@@ -858,8 +855,6 @@ static int timblogiw_remove(struct platform_device *pdev)
kfree(lw);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index a794cd6c4441..b4f9d03636e3 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -17,7 +17,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/ov7670.h>
#include <media/videobuf-dma-sg.h>
@@ -805,20 +804,6 @@ static const struct v4l2_file_operations viacam_fops = {
* The long list of v4l2 ioctl ops
*/
-static int viacam_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *ident)
-{
- struct via_camera *cam = priv;
-
- ident->ident = V4L2_IDENT_NONE;
- ident->revision = 0;
- if (v4l2_chip_match_host(&ident->match)) {
- ident->ident = V4L2_IDENT_VIA_VX855;
- return 0;
- }
- return sensor_call(cam, core, g_chip_ident, ident);
-}
-
/*
* Only one input.
*/
@@ -852,6 +837,12 @@ static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std)
return 0;
}
+static int viacam_g_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+ *std = V4L2_STD_NTSC_M;
+ return 0;
+}
+
/*
* Video format stuff. Here is our default format until
* user space messes with things.
@@ -1174,11 +1165,11 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
- .vidioc_g_chip_ident = viacam_g_chip_ident,
.vidioc_enum_input = viacam_enum_input,
.vidioc_g_input = viacam_g_input,
.vidioc_s_input = viacam_s_input,
.vidioc_s_std = viacam_s_std,
+ .vidioc_g_std = viacam_g_std,
.vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap,
@@ -1266,7 +1257,6 @@ static struct video_device viacam_v4l_template = {
.name = "via-camera",
.minor = -1,
.tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M,
.fops = &viacam_fops,
.ioctl_ops = &viacam_ioctl_ops,
.release = video_device_release_empty, /* Check this */
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 4c9ae767fb31..21db23b196be 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -93,7 +93,7 @@ static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play)
/* If bit 4 is set, then tune to the frequency.
If bit 3 is set, then unmute; if bit 2 is set, then mute.
If bit 1 is set, then enter idle mode; if bit 0 is set,
- then enter transit mode.
+ then enter transmit mode.
*/
radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) |
(freq ? 0x10 : 0);
@@ -350,7 +350,6 @@ static int usb_keene_probe(struct usb_interface *intf,
radio->pa = 118;
radio->tx = 0x32;
radio->stereo = true;
- radio->curfreq = 95.16 * FREQ_MUL;
if (hdl->error) {
retval = hdl->error;
@@ -383,6 +382,10 @@ static int usb_keene_probe(struct usb_interface *intf,
video_set_drvdata(&radio->vdev, radio);
set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+ /* at least 11ms is needed in order to settle hardware */
+ msleep(20);
+ keene_cmd_main(radio, 95.16 * FREQ_MUL, false);
+
retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
if (retval < 0) {
dev_err(&intf->dev, "could not register video device\n");
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index adfcc61bdf0b..6f4318ff0db3 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -27,6 +27,8 @@
#include <linux/io.h> /* outb, outb_p */
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include "lm7000.h"
MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
@@ -44,10 +46,11 @@ module_param(radio_nr, int, 0);
struct fmi
{
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
struct video_device vdev;
int io;
bool mute;
- unsigned long curfreq; /* freq in kHz */
+ u32 curfreq; /* freq in kHz */
struct mutex lock;
};
@@ -55,8 +58,8 @@ static struct fmi fmi_card;
static struct pnp_dev *dev;
bool pnp_attached;
-#define RSF16_MINFREQ (87 * 16000)
-#define RSF16_MAXFREQ (108 * 16000)
+#define RSF16_MINFREQ (87U * 16000)
+#define RSF16_MAXFREQ (108U * 16000)
#define FMI_BIT_TUN_CE (1 << 0)
#define FMI_BIT_TUN_CLK (1 << 1)
@@ -115,13 +118,22 @@ static inline int fmi_getsigstr(struct fmi *fmi)
return (res & 2) ? 0 : 0xFFFF;
}
+static void fmi_set_freq(struct fmi *fmi)
+{
+ fmi->curfreq = clamp(fmi->curfreq, RSF16_MINFREQ, RSF16_MAXFREQ);
+ /* rounding in steps of 800 to match the freq
+ that will be used */
+ lm7000_set_freq((fmi->curfreq / 800) * 800, fmi, fmi_set_pins);
+}
+
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ strlcpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info));
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -157,12 +169,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- if (f->frequency < RSF16_MINFREQ ||
- f->frequency > RSF16_MAXFREQ)
- return -EINVAL;
- /* rounding in steps of 800 to match the freq
- that will be used */
- lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins);
+
+ fmi->curfreq = f->frequency;
+ fmi_set_freq(fmi);
+
return 0;
}
@@ -178,74 +188,31 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int fmi_s_ctrl(struct v4l2_ctrl *ctrl)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct fmi *fmi = video_drvdata(file);
+ struct fmi *fmi = container_of(ctrl->handler, struct fmi, hdl);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = fmi->mute;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct fmi *fmi = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
+ if (ctrl->val)
fmi_mute(fmi);
else
fmi_unmute(fmi);
- fmi->mute = ctrl->value;
+ fmi->mute = ctrl->val;
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,
- const struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
+static const struct v4l2_ctrl_ops fmi_ctrl_ops = {
+ .s_ctrl = fmi_s_ctrl,
+};
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
};
@@ -253,15 +220,11 @@ static const struct v4l2_ioctl_ops fmi_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,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* ladis: this is my card. does any other types exist? */
@@ -311,6 +274,7 @@ static int __init fmi_init(void)
{
struct fmi *fmi = &fmi_card;
struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
+ struct v4l2_ctrl_handler *hdl = &fmi->hdl;
int res, i;
int probe_ports[] = { 0, 0x284, 0x384 };
@@ -363,19 +327,35 @@ static int __init fmi_init(void)
return res;
}
+ v4l2_ctrl_handler_init(hdl, 1);
+ v4l2_ctrl_new_std(hdl, &fmi_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_dev->ctrl_handler = hdl;
+ if (hdl->error) {
+ res = hdl->error;
+ v4l2_err(v4l2_dev, "Could not register controls\n");
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(v4l2_dev);
+ return res;
+ }
+
strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
fmi->vdev.v4l2_dev = v4l2_dev;
fmi->vdev.fops = &fmi_fops;
fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
fmi->vdev.release = video_device_release_empty;
+ set_bit(V4L2_FL_USE_FH_PRIO, &fmi->vdev.flags);
video_set_drvdata(&fmi->vdev, fmi);
mutex_init(&fmi->lock);
- /* mute card - prevents noisy bootups */
- fmi_mute(fmi);
+ /* mute card and set default frequency */
+ fmi->mute = 1;
+ fmi->curfreq = RSF16_MINFREQ;
+ fmi_set_freq(fmi);
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_ctrl_handler_free(hdl);
v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2);
if (pnp_attached)
@@ -391,6 +371,7 @@ static void __exit fmi_exit(void)
{
struct fmi *fmi = &fmi_card;
+ v4l2_ctrl_handler_free(&fmi->hdl);
video_unregister_device(&fmi->vdev);
v4l2_device_unregister(&fmi->v4l2_dev);
release_region(fmi->io, 2);
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 9dc8bafe6486..9c9084cb99f7 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1018,16 +1018,6 @@ static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
return retval;
}
-static int si476x_radio_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
- v4l2_chip_match_host(&chip->match))
- return 0;
- return -EINVAL;
-}
-
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int si476x_radio_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
@@ -1203,7 +1193,6 @@ static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = si476x_radio_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = si476x_radio_g_register,
.vidioc_s_register = si476x_radio_s_register,
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 38d563d62595..036e2f54f4db 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -39,6 +39,9 @@
#include <linux/i2c.h> /* I2C */
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#define DRIVER_VERSION "0.0.2"
@@ -57,8 +60,8 @@
/* Frequency limits in MHz -- these are European values. For Japanese
devices, that would be 76000 and 91000. */
-#define FREQ_MIN 87500
-#define FREQ_MAX 108000
+#define FREQ_MIN 87500U
+#define FREQ_MAX 108000U
#define FREQ_MUL 16
/* TEA5764 registers */
@@ -138,8 +141,10 @@ static int radio_nr = -1;
static int use_xtal = RADIO_TEA5764_XTAL;
struct tea5764_device {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
struct i2c_client *i2c_client;
- struct video_device *videodev;
+ struct video_device vdev;
struct tea5764_regs regs;
struct mutex mutex;
};
@@ -187,18 +192,6 @@ static int tea5764_i2c_write(struct tea5764_device *radio)
return 0;
}
-/* V4L2 code related */
-static struct v4l2_queryctrl radio_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- }
-};
-
static void tea5764_power_up(struct tea5764_device *radio)
{
struct tea5764_regs *r = &radio->regs;
@@ -291,23 +284,19 @@ static void tea5764_mute(struct tea5764_device *radio, int on)
tea5764_i2c_write(radio);
}
-static int tea5764_is_muted(struct tea5764_device *radio)
-{
- return radio->regs.tnctrl & TEA5764_TNCTRL_MU;
-}
-
/* V4L2 vidioc */
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
struct tea5764_device *radio = video_drvdata(file);
- struct video_device *dev = radio->videodev;
+ struct video_device *dev = &radio->vdev;
strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
strlcpy(v->card, dev->name, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info),
"I2C:%s", dev_name(&dev->dev));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -320,8 +309,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- memset(v, 0, sizeof(*v));
- strcpy(v->name, "FM");
+ strlcpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
tea5764_i2c_read(radio);
v->rangelow = FREQ_MIN * FREQ_MUL;
@@ -354,19 +342,23 @@ static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
struct tea5764_device *radio = video_drvdata(file);
+ unsigned freq = f->frequency;
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- if (f->frequency == 0) {
+ if (freq == 0) {
/* We special case this as a power down control. */
tea5764_power_down(radio);
- }
- if (f->frequency < (FREQ_MIN * FREQ_MUL))
- return -EINVAL;
- if (f->frequency > (FREQ_MAX * FREQ_MUL))
+ /* Yes, that's what is returned in this case. This
+ whole special case is non-compliant and should really
+ be replaced with something better, but changing this
+ might well break code that depends on this behavior.
+ So we keep it as-is. */
return -EINVAL;
+ }
+ clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
tea5764_power_up(radio);
- tea5764_tune(radio, (f->frequency * 125) / 2);
+ tea5764_tune(radio, (freq * 125) / 2);
return 0;
}
@@ -379,7 +371,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
if (f->tuner != 0)
return -EINVAL;
tea5764_i2c_read(radio);
- memset(f, 0, sizeof(*f));
f->type = V4L2_TUNER_RADIO;
if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
f->frequency = (tea5764_get_freq(radio) * 2) / 125;
@@ -389,83 +380,29 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct tea5764_device *radio = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- tea5764_i2c_read(radio);
- ctrl->value = tea5764_is_muted(radio) ? 1 : 0;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct tea5764_device *radio = video_drvdata(file);
+ struct tea5764_device *radio =
+ container_of(ctrl->handler, struct tea5764_device, ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- tea5764_mute(radio, ctrl->value);
+ tea5764_mute(radio, ctrl->val);
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)
-{
- if (i != 0)
- return -EINVAL;
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- if (a->index > 1)
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *a)
-{
- if (a->index != 0)
- return -EINVAL;
-
- return 0;
-}
+static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
+ .s_ctrl = tea5764_s_ctrl,
+};
/* File system interface */
static const struct v4l2_file_operations tea5764_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
};
@@ -473,15 +410,11 @@ static const struct v4l2_ioctl_ops tea5764_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,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* V4L2 interface */
@@ -489,7 +422,7 @@ static struct video_device tea5764_radio_template = {
.name = "TEA5764 FM-Radio",
.fops = &tea5764_fops,
.ioctl_ops = &tea5764_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
};
/* I2C probe: check if the device exists and register with v4l if it is */
@@ -497,6 +430,8 @@ static int tea5764_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tea5764_device *radio;
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_ctrl_handler *hdl;
struct tea5764_regs *r;
int ret;
@@ -505,31 +440,45 @@ static int tea5764_i2c_probe(struct i2c_client *client,
if (!radio)
return -ENOMEM;
+ v4l2_dev = &radio->v4l2_dev;
+ ret = v4l2_device_register(&client->dev, v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+ goto errfr;
+ }
+
+ hdl = &radio->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 1);
+ v4l2_ctrl_new_std(hdl, &tea5764_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_dev->ctrl_handler = hdl;
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_err(v4l2_dev, "Could not register controls\n");
+ goto errunreg;
+ }
+
mutex_init(&radio->mutex);
radio->i2c_client = client;
ret = tea5764_i2c_read(radio);
if (ret)
- goto errfr;
+ goto errunreg;
r = &radio->regs;
PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
if (r->chipid != TEA5764_CHIPID ||
(r->manid & 0x0fff) != TEA5764_MANID) {
PWARN("This chip is not a TEA5764!");
ret = -EINVAL;
- goto errfr;
+ goto errunreg;
}
- radio->videodev = video_device_alloc();
- if (!(radio->videodev)) {
- ret = -ENOMEM;
- goto errfr;
- }
- memcpy(radio->videodev, &tea5764_radio_template,
- sizeof(tea5764_radio_template));
+ radio->vdev = tea5764_radio_template;
i2c_set_clientdata(client, radio);
- video_set_drvdata(radio->videodev, radio);
- radio->videodev->lock = &radio->mutex;
+ video_set_drvdata(&radio->vdev, radio);
+ radio->vdev.lock = &radio->mutex;
+ radio->vdev.v4l2_dev = v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
/* initialize and power off the chip */
tea5764_i2c_read(radio);
@@ -537,16 +486,17 @@ static int tea5764_i2c_probe(struct i2c_client *client,
tea5764_mute(radio, 1);
tea5764_power_down(radio);
- ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ ret = video_register_device(&radio->vdev, VFL_TYPE_RADIO, radio_nr);
if (ret < 0) {
PWARN("Could not register video device!");
- goto errrel;
+ goto errunreg;
}
PINFO("registered.");
return 0;
-errrel:
- video_device_release(radio->videodev);
+errunreg:
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(v4l2_dev);
errfr:
kfree(radio);
return ret;
@@ -559,7 +509,9 @@ static int tea5764_i2c_remove(struct i2c_client *client)
PDEBUG("remove");
if (radio) {
tea5764_power_down(radio);
- video_unregister_device(radio->videodev);
+ video_unregister_device(&radio->vdev);
+ v4l2_ctrl_handler_free(&radio->ctrl_handler);
+ v4l2_device_unregister(&radio->v4l2_dev);
kfree(radio);
}
return 0;
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index bb7b143b65d1..0817964d9172 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -19,6 +19,8 @@
#include <linux/io.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -44,7 +46,8 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv,
strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -62,34 +65,6 @@ static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
}
-static int timbradio_vidioc_g_input(struct file *filp, void *priv,
- unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int timbradio_vidioc_s_input(struct file *filp, void *priv,
- unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int timbradio_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 timbradio_vidioc_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
@@ -104,44 +79,22 @@ static int timbradio_vidioc_g_frequency(struct file *file, void *priv,
return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);
}
-static int timbradio_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct timbradio *tr = video_drvdata(file);
- return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);
-}
-
-static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct timbradio *tr = video_drvdata(file);
- return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);
-}
-
-static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct timbradio *tr = video_drvdata(file);
- return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);
-}
-
static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
.vidioc_querycap = timbradio_vidioc_querycap,
.vidioc_g_tuner = timbradio_vidioc_g_tuner,
.vidioc_s_tuner = timbradio_vidioc_s_tuner,
.vidioc_g_frequency = timbradio_vidioc_g_frequency,
.vidioc_s_frequency = timbradio_vidioc_s_frequency,
- .vidioc_g_input = timbradio_vidioc_g_input,
- .vidioc_s_input = timbradio_vidioc_s_input,
- .vidioc_g_audio = timbradio_vidioc_g_audio,
- .vidioc_s_audio = timbradio_vidioc_s_audio,
- .vidioc_queryctrl = timbradio_vidioc_queryctrl,
- .vidioc_g_ctrl = timbradio_vidioc_g_ctrl,
- .vidioc_s_ctrl = timbradio_vidioc_s_ctrl
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
};
@@ -173,6 +126,7 @@ static int timbradio_probe(struct platform_device *pdev)
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &tr->video_dev.flags);
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
@@ -181,6 +135,15 @@ static int timbradio_probe(struct platform_device *pdev)
tr->video_dev.v4l2_dev = &tr->v4l2_dev;
+ tr->sd_tuner = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+ i2c_get_adapter(pdata->i2c_adapter), pdata->tuner, NULL);
+ tr->sd_dsp = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+ i2c_get_adapter(pdata->i2c_adapter), pdata->dsp, NULL);
+ if (tr->sd_tuner == NULL || tr->sd_dsp == NULL)
+ goto err_video_req;
+
+ tr->v4l2_dev.ctrl_handler = tr->sd_dsp->ctrl_handler;
+
err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);
if (err) {
dev_err(&pdev->dev, "Error reg video\n");
@@ -193,7 +156,6 @@ static int timbradio_probe(struct platform_device *pdev)
return 0;
err_video_req:
- video_device_release_empty(&tr->video_dev);
v4l2_device_unregister(&tr->v4l2_dev);
err:
dev_err(&pdev->dev, "Failed to register: %d\n", err);
@@ -206,10 +168,7 @@ static int timbradio_remove(struct platform_device *pdev)
struct timbradio *tr = platform_get_drvdata(pdev);
video_unregister_device(&tr->video_dev);
- video_device_release_empty(&tr->video_dev);
-
v4l2_device_unregister(&tr->v4l2_dev);
-
return 0;
}
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index 06c06cc9ff25..ec805b09c608 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -25,7 +25,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#define DRIVER_NAME "saa7706h"
@@ -127,6 +127,7 @@
struct saa7706h_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
unsigned muted;
};
@@ -317,51 +318,32 @@ static int saa7706h_mute(struct v4l2_subdev *sd)
return err;
}
-static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+static int saa7706h_s_ctrl(struct v4l2_ctrl *ctrl)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
- return -EINVAL;
-}
-
-static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct saa7706h_state *state = to_state(sd);
+ struct saa7706h_state *state =
+ container_of(ctrl->handler, struct saa7706h_state, hdl);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = state->muted;
- return 0;
+ if (ctrl->val)
+ return saa7706h_mute(&state->sd);
+ return saa7706h_unmute(&state->sd);
}
return -EINVAL;
}
-static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- return saa7706h_mute(sd);
- return saa7706h_unmute(sd);
- }
- return -EINVAL;
-}
-
-static int saa7706h_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0);
-}
+static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = {
+ .s_ctrl = saa7706h_s_ctrl,
+};
static const struct v4l2_subdev_core_ops saa7706h_core_ops = {
- .g_chip_ident = saa7706h_g_chip_ident,
- .queryctrl = saa7706h_queryctrl,
- .g_ctrl = saa7706h_g_ctrl,
- .s_ctrl = saa7706h_s_ctrl,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_ops saa7706h_ops = {
@@ -393,13 +375,20 @@ static int saa7706h_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &saa7706h_ops);
+ v4l2_ctrl_handler_init(&state->hdl, 4);
+ v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ sd->ctrl_handler = &state->hdl;
+ err = state->hdl.error;
+ if (err)
+ goto err;
+
/* check the rom versions */
err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER);
if (err < 0)
goto err;
if (err != SUPPORTED_DSP1_ROM_VER)
v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err);
-
state->muted = 1;
/* startup in a muted state */
@@ -411,6 +400,7 @@ static int saa7706h_probe(struct i2c_client *client,
err:
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&state->hdl);
kfree(to_state(sd));
printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err);
@@ -421,9 +411,11 @@ err:
static int saa7706h_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct saa7706h_state *state = to_state(sd);
saa7706h_mute(sd);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&state->hdl);
kfree(to_state(sd));
return 0;
}
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 82c6c9475d7c..06ac69245ca1 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -25,14 +25,13 @@
#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#define DRIVER_NAME "tef6862"
#define FREQ_MUL 16000
-#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
-#define TEF6862_HI_FREQ (108 * FREQ_MUL)
+#define TEF6862_LO_FREQ (875U * FREQ_MUL / 10)
+#define TEF6862_HI_FREQ (108U * FREQ_MUL)
/* Write mode sub addresses */
#define WM_SUB_BANDWIDTH 0x0
@@ -105,6 +104,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
{
struct tef6862_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ unsigned freq = f->frequency;
u16 pll;
u8 i2cmsg[3];
int err;
@@ -112,7 +112,8 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
if (f->tuner != 0)
return -EINVAL;
- pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
+ clamp(freq, TEF6862_LO_FREQ, TEF6862_HI_FREQ);
+ pll = 1964 + ((freq - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
i2cmsg[1] = (pll >> 8) & 0xff;
i2cmsg[2] = pll & 0xff;
@@ -121,7 +122,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
if (err != sizeof(i2cmsg))
return err < 0 ? err : -EIO;
- state->freq = f->frequency;
+ state->freq = freq;
return 0;
}
@@ -136,14 +137,6 @@ static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
return 0;
}
-static int tef6862_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0);
-}
-
static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
.g_tuner = tef6862_g_tuner,
.s_tuner = tef6862_s_tuner,
@@ -151,12 +144,7 @@ static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
.g_frequency = tef6862_g_frequency,
};
-static const struct v4l2_subdev_core_ops tef6862_core_ops = {
- .g_chip_ident = tef6862_g_chip_ident,
-};
-
static const struct v4l2_subdev_ops tef6862_ops = {
- .core = &tef6862_core_ops,
.tuner = &tef6862_tuner_ops,
};
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
index aac0f025f767..a587c9bac930 100644
--- a/drivers/media/radio/wl128x/fmdrv.h
+++ b/drivers/media/radio/wl128x/fmdrv.h
@@ -30,6 +30,7 @@
#include <linux/timer.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#define FM_DRV_VERSION "0.1.1"
@@ -202,6 +203,7 @@ struct fmtx_data {
/* FM driver operation structure */
struct fmdev {
struct video_device *radio_dev; /* V4L2 video device pointer */
+ struct v4l2_device v4l2_dev; /* V4L2 top level struct */
struct snd_card *card; /* Card which holds FM mixer controls */
u16 asci_id;
spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index a002234ed5de..253f307f0b37 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -715,7 +715,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
struct fm_rdsdata_format rds_fmt;
struct fm_rds *rds = &fmdev->rx.rds;
unsigned long group_idx, flags;
- u8 *rds_data, meta_data, tmpbuf[3];
+ u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE];
u8 type, blk_idx;
u16 cur_picode;
u32 rds_len;
@@ -1073,6 +1073,7 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
u8 __user *buf, size_t count)
{
u32 block_count;
+ u8 tmpbuf[FM_RDS_BLK_SIZE];
unsigned long flags;
int ret;
@@ -1087,29 +1088,32 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
}
/* Calculate block count from byte count */
- count /= 3;
+ count /= FM_RDS_BLK_SIZE;
block_count = 0;
ret = 0;
- spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
-
while (block_count < count) {
- if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx)
- break;
+ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
- if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
- FM_RDS_BLK_SIZE))
+ if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) {
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
break;
-
+ }
+ memcpy(tmpbuf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
+ FM_RDS_BLK_SIZE);
fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE;
if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size)
fmdev->rx.rds.rd_idx = 0;
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+ if (copy_to_user(buf, tmpbuf, FM_RDS_BLK_SIZE))
+ break;
+
block_count++;
buf += FM_RDS_BLK_SIZE;
ret += FM_RDS_BLK_SIZE;
}
- spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
return ret;
}
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 5dec323f4247..b55012c11842 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -533,6 +533,11 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
struct v4l2_ctrl *ctrl;
int ret;
+ strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name));
+ ret = v4l2_device_register(NULL, &fmdev->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
/* Init mutex for core locking */
mutex_init(&fmdev->mutex);
@@ -549,6 +554,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
video_set_drvdata(gradio_dev, fmdev);
gradio_dev->lock = &fmdev->mutex;
+ gradio_dev->v4l2_dev = &fmdev->v4l2_dev;
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
@@ -611,5 +617,7 @@ void *fm_v4l2_deinit_video_device(void)
/* Unregister RADIO device from V4L2 subsystem */
video_unregister_device(gradio_dev);
+ v4l2_device_unregister(&fmdev->v4l2_dev);
+
return fmdev;
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8b82ae9bd686..07aacfa5903d 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -178,7 +178,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
return 0;
err_request_irq:
- platform_set_drvdata(pdev, NULL);
rc_unregister_device(rcdev);
rcdev = NULL;
err_register_rc_device:
@@ -196,7 +195,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
- platform_set_drvdata(pdev, NULL);
rc_unregister_device(gpio_dev->rcdev);
gpio_free(gpio_dev->gpio_nr);
kfree(gpio_dev);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 5ab94ea4bc28..b1cde8c0422b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-budget-ci-old.o \
rc-cinergy-1400.o \
rc-cinergy.o \
+ rc-delock-61959.o \
rc-dib0700-nec.o \
rc-dib0700-rc5.o \
rc-digitalnow-tinytwin.o \
diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c
new file mode 100644
index 000000000000..01bed864f09d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-delock-61959.c
@@ -0,0 +1,83 @@
+/* rc-delock-61959.c - Keytable for Delock
+ *
+ * Copyright (c) 2013 by Jakob Haufe <sur5r@sur5r.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
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * Keytable for remote provided with Delock 61959
+ */
+static struct rc_map_table delock_61959[] = {
+ { 0x866b16, KEY_POWER2 }, /* Power */
+ { 0x866b0c, KEY_POWER }, /* Shut Down */
+
+ { 0x866b00, KEY_1},
+ { 0x866b01, KEY_2},
+ { 0x866b02, KEY_3},
+ { 0x866b03, KEY_4},
+ { 0x866b04, KEY_5},
+ { 0x866b05, KEY_6},
+ { 0x866b06, KEY_7},
+ { 0x866b07, KEY_8},
+ { 0x866b08, KEY_9},
+ { 0x866b14, KEY_0},
+
+ { 0x866b0a, KEY_ZOOM}, /* Full Screen */
+ { 0x866b10, KEY_CAMERA}, /* Photo */
+ { 0x866b0e, KEY_CHANNEL}, /* circular arrow / Recall */
+ { 0x866b13, KEY_ESC}, /* Back */
+
+ { 0x866b20, KEY_UP},
+ { 0x866b21, KEY_DOWN},
+ { 0x866b42, KEY_LEFT},
+ { 0x866b43, KEY_RIGHT},
+ { 0x866b0b, KEY_OK},
+
+ { 0x866b11, KEY_CHANNELUP},
+ { 0x866b1b, KEY_CHANNELDOWN},
+
+ { 0x866b12, KEY_VOLUMEUP},
+ { 0x866b48, KEY_VOLUMEDOWN},
+ { 0x866b44, KEY_MUTE},
+
+ { 0x866b1a, KEY_RECORD},
+ { 0x866b41, KEY_PLAY},
+ { 0x866b40, KEY_STOP},
+ { 0x866b19, KEY_PAUSE},
+ { 0x866b1c, KEY_FASTFORWARD}, /* >> / FWD */
+ { 0x866b1e, KEY_REWIND}, /* << / REW */
+
+};
+
+static struct rc_map_list delock_61959_map = {
+ .map = {
+ .scan = delock_61959,
+ .size = ARRAY_SIZE(delock_61959),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_DELOCK_61959,
+ }
+};
+
+static int __init init_rc_map_delock_61959(void)
+{
+ return rc_map_register(&delock_61959_map);
+}
+
+static void __exit exit_rc_map_delock_61959(void)
+{
+ rc_map_unregister(&delock_61959_map);
+}
+
+module_init(init_rc_map_delock_61959)
+module_exit(exit_rc_map_delock_61959)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jakob Haufe <sur5r@sur5r.net>");
+MODULE_DESCRIPTION("Delock 61959 remote keytable");
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index 4835021aa3b6..1c23666468cf 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -364,8 +364,8 @@ static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val,
}
if (len <= 0)
return;
- if (len > NUM_REGS)
- len = NUM_REGS;
+ if (len > NUM_REGS - r)
+ len = NUM_REGS - r;
tuner_dbg("%s: prev reg=%02x len=%d: %*ph\n",
__func__, r + REG_SHADOW_START, len, len, val);
@@ -1857,9 +1857,9 @@ static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
int reg18, reg19, reg1f;
if (priv->cfg->xtal > 24000000)
- ring_ref = priv->cfg->xtal / 2;
+ ring_ref = priv->cfg->xtal / 2000;
else
- ring_ref = priv->cfg->xtal;
+ ring_ref = priv->cfg->xtal / 1000;
n_ring = 15;
for (n = 0; n < 16; n++) {
@@ -2256,7 +2256,6 @@ static int r820t_release(struct dvb_frontend *fe)
mutex_unlock(&r820t_list_mutex);
- kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
@@ -2311,8 +2310,6 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
break;
}
- memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops));
-
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -2327,15 +2324,14 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
tuner_info("Rafael Micro r820t successfully identified\n");
- fe->tuner_priv = priv;
- memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
mutex_unlock(&r820t_list_mutex);
+ memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
return fe;
err:
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 0a7d520636a9..cfe8056b91aa 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -1,6 +1,7 @@
+if USB && MEDIA_SUPPORT
+
menuconfig MEDIA_USB_SUPPORT
bool "Media USB Adapters"
- depends on USB && MEDIA_SUPPORT
help
Enable media drivers for USB bus.
If you have such devices, say Y.
@@ -17,6 +18,7 @@ source "drivers/media/usb/zr364xx/Kconfig"
source "drivers/media/usb/stkwebcam/Kconfig"
source "drivers/media/usb/s2255/Kconfig"
source "drivers/media/usb/sn9c102/Kconfig"
+source "drivers/media/usb/usbtv/Kconfig"
endif
if MEDIA_ANALOG_TV_SUPPORT
@@ -52,3 +54,4 @@ source "drivers/media/usb/em28xx/Kconfig"
endif
endif #MEDIA_USB_SUPPORT
+endif #USB
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
index 7f51d7e5f739..0935f47497a6 100644
--- a/drivers/media/usb/Makefile
+++ b/drivers/media/usb/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_VIDEO_STK1160) += stk1160/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_USBTV) += usbtv/
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 75ac9947cdac..f6154546b5c0 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -36,7 +36,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
#include <media/tuner.h>
#include "au0828.h"
#include "au0828-reg.h"
@@ -1638,26 +1637,6 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
-
- if (v4l2_chip_match_host(&chip->match)) {
- chip->ident = V4L2_IDENT_AU0828;
- return 0;
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
- if (chip->ident == V4L2_IDENT_NONE)
- return -EINVAL;
-
- return 0;
-}
-
static int vidioc_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cc)
{
@@ -1779,16 +1758,8 @@ static int vidioc_g_register(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
reg->val = au0828_read(dev, reg->reg);
+ reg->size = 1;
return 0;
}
@@ -1798,14 +1769,6 @@ static int vidioc_s_register(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
return au0828_writereg(dev, reg->reg, reg->val);
}
#endif
@@ -1943,7 +1906,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_log_status = vidioc_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index f548db8043d4..2f63029e7a36 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1840,7 +1840,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_log_status = vidioc_log_status,
- .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = cx231xx_g_register,
.vidioc_s_register = cx231xx_s_register,
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 235ba657d52e..89de00bf4f82 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -35,7 +35,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
#include "cx231xx.h"
#include "cx231xx-dif.h"
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 13249e5a7891..27948e1798eb 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -29,7 +29,6 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
#include "dvb-usb-ids.h"
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index 1340ff268817..c02794274f51 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -32,7 +32,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index cd221474e1b9..990626101718 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -36,7 +36,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -1228,179 +1227,93 @@ int cx231xx_s_frequency(struct file *file, void *priv,
return rc;
}
-int cx231xx_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+int cx231xx_g_chip_info(struct file *file, void *fh,
+ struct v4l2_dbg_chip_info *chip)
{
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match))
- chip->ident = V4L2_IDENT_CX23100;
+ switch (chip->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ return 0;
+ case 1: /* AFE - read byte */
+ strlcpy(chip->name, "AFE (byte)", sizeof(chip->name));
+ return 0;
+ case 2: /* Video Block - read byte */
+ strlcpy(chip->name, "Video (byte)", sizeof(chip->name));
+ return 0;
+ case 3: /* I2S block - read byte */
+ strlcpy(chip->name, "I2S (byte)", sizeof(chip->name));
+ return 0;
+ case 4: /* AFE - read dword */
+ strlcpy(chip->name, "AFE (dword)", sizeof(chip->name));
+ return 0;
+ case 5: /* Video Block - read dword */
+ strlcpy(chip->name, "Video (dword)", sizeof(chip->name));
+ return 0;
+ case 6: /* I2S Block - read dword */
+ strlcpy(chip->name, "I2S (dword)", sizeof(chip->name));
return 0;
}
return -EINVAL;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-/*
- -R, --list-registers=type=<host/i2cdrv/i2caddr>,
- chip=<chip>[,min=<addr>,max=<addr>]
- dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
- -r, --set-register=type=<host/i2cdrv/i2caddr>,
- chip=<chip>,reg=<addr>,val=<val>
- set the register [VIDIOC_DBG_S_REGISTER]
-
- if type == host, then <chip> is the hosts chip ID (default 0)
- if type == i2cdrv (default), then <chip> is the I2C driver name or ID
- if type == i2caddr, then <chip> is the 7-bit I2C address
-*/
-
int cx231xx_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- int ret = 0;
+ int ret;
u8 value[4] = { 0, 0, 0, 0 };
u32 data = 0;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- switch (reg->match.addr) {
- case 0: /* Cx231xx - internal registers */
- ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
- (u16)reg->reg, value, 4);
- reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
- break;
- case 1: /* AFE - read byte */
- ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2, &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 14: /* AFE - read dword */
- ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- case 2: /* Video Block - read byte */
- ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2, &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 24: /* Video Block - read dword */
- ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- case 3: /* I2S block - read byte */
- ret = cx231xx_read_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 34: /* I2S Block - read dword */
- ret =
- cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- }
- return ret < 0 ? ret : 0;
-
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- call_all(dev, core, g_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
- switch (reg->match.addr) {
- case 0: /* Cx231xx - internal registers */
- ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
- (u16)reg->reg, value, 4);
- reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
-
- break;
- case 0x600:/* AFE - read byte */
- ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
-
- case 0x880:/* Video Block - read byte */
- if (reg->reg < 0x0b) {
- ret = cx231xx_read_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- } else {
- ret = cx231xx_read_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- &data, 4 , 0);
- reg->val = le32_to_cpu(data);
- }
- break;
- case 0x980:
- ret = cx231xx_read_i2c_master(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0x400:
- ret =
- cx231xx_read_i2c_master(dev, 0x40,
- (u16)reg->reg, 1,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0xc01:
- ret =
- cx231xx_read_i2c_master(dev, 0xc0,
- (u16)reg->reg, 2,
- &data, 38, 1);
- reg->val = le32_to_cpu(data);
- break;
- case 0x022:
- ret =
- cx231xx_read_i2c_master(dev, 0x02,
- (u16)reg->reg, 1,
- &data, 1, 2);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0x322:
- ret = cx231xx_read_i2c_master(dev,
- 0x32,
- (u16)reg->reg, 1,
- &data, 4 , 2);
- reg->val = le32_to_cpu(data);
- break;
- case 0x342:
- ret = cx231xx_read_i2c_master(dev,
- 0x34,
- (u16)reg->reg, 1,
- &data, 4 , 2);
- reg->val = le32_to_cpu(data);
- break;
-
- default:
- cx231xx_info("no match device address!!\n");
- break;
- }
- return ret < 0 ? ret : 0;
- /*return -EINVAL;*/
+ switch (reg->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ (u16)reg->reg, value, 4);
+ reg->val = value[0] | value[1] << 8 |
+ value[2] << 16 | value[3] << 24;
+ reg->size = 4;
+ break;
+ case 1: /* AFE - read byte */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = data;
+ reg->size = 1;
+ break;
+ case 2: /* Video Block - read byte */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = data;
+ reg->size = 1;
+ break;
+ case 3: /* I2S block - read byte */
+ ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, &data, 1);
+ reg->val = data;
+ reg->size = 1;
+ break;
+ case 4: /* AFE - read dword */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = data;
+ reg->size = 4;
+ break;
+ case 5: /* Video Block - read dword */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = data;
+ reg->size = 4;
+ break;
+ case 6: /* I2S Block - read dword */
+ ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, &data, 4);
+ reg->val = data;
+ reg->size = 4;
+ break;
default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ return -EINVAL;
}
-
- call_all(dev, core, g_register, reg);
-
- return ret;
+ return ret < 0 ? ret : 0;
}
int cx231xx_s_register(struct file *file, void *priv,
@@ -1408,165 +1321,46 @@ int cx231xx_s_register(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- int ret = 0;
- __le64 buf;
- u32 value;
+ int ret;
u8 data[4] = { 0, 0, 0, 0 };
- buf = cpu_to_le64(reg->val);
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- {
- value = (u32) buf & 0xffffffff;
-
- switch (reg->match.addr) {
- case 0: /* cx231xx internal registers */
- data[0] = (u8) value;
- data[1] = (u8) (value >> 8);
- data[2] = (u8) (value >> 16);
- data[3] = (u8) (value >> 24);
- ret = cx231xx_write_ctrl_reg(dev,
- VRT_SET_REGISTER,
- (u16)reg->reg, data,
- 4);
- break;
- case 1: /* AFE - read byte */
- ret = cx231xx_write_i2c_data(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 1);
- break;
- case 14: /* AFE - read dword */
- ret = cx231xx_write_i2c_data(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 4);
- break;
- case 2: /* Video Block - read byte */
- ret =
- cx231xx_write_i2c_data(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 1);
- break;
- case 24: /* Video Block - read dword */
- ret =
- cx231xx_write_i2c_data(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 4);
- break;
- case 3: /* I2S block - read byte */
- ret =
- cx231xx_write_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 1);
- break;
- case 34: /* I2S block - read dword */
- ret =
- cx231xx_write_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 4);
- break;
- }
- }
- return ret < 0 ? ret : 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- {
- value = (u32) buf & 0xffffffff;
-
- switch (reg->match.addr) {
- case 0:/*cx231xx internal registers*/
- data[0] = (u8) value;
- data[1] = (u8) (value >> 8);
- data[2] = (u8) (value >> 16);
- data[3] = (u8) (value >> 24);
- ret = cx231xx_write_ctrl_reg(dev,
- VRT_SET_REGISTER,
- (u16)reg->reg, data,
- 4);
- break;
- case 0x600:/* AFE - read byte */
- ret = cx231xx_write_i2c_master(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 1 , 0);
- break;
-
- case 0x880:/* Video Block - read byte */
- if (reg->reg < 0x0b)
- cx231xx_write_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 1, 0);
- else
- cx231xx_write_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 4, 0);
- break;
- case 0x980:
- ret =
- cx231xx_write_i2c_master(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 1, 0);
- break;
- case 0x400:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x40,
- (u16)reg->reg, 1,
- value, 1, 0);
- break;
- case 0xc01:
- ret =
- cx231xx_write_i2c_master(dev,
- 0xc0,
- (u16)reg->reg, 1,
- value, 1, 1);
- break;
-
- case 0x022:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x02,
- (u16)reg->reg, 1,
- value, 1, 2);
- break;
- case 0x322:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x32,
- (u16)reg->reg, 1,
- value, 4, 2);
- break;
-
- case 0x342:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x34,
- (u16)reg->reg, 1,
- value, 4, 2);
- break;
- default:
- cx231xx_info("no match device address, "
- "the value is %x\n", reg->match.addr);
- break;
-
- }
-
- }
- default:
+ switch (reg->match.addr) {
+ case 0: /* cx231xx internal registers */
+ data[0] = (u8) reg->val;
+ data[1] = (u8) (reg->val >> 8);
+ data[2] = (u8) (reg->val >> 16);
+ data[3] = (u8) (reg->val >> 24);
+ ret = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ (u16)reg->reg, data, 4);
+ break;
+ case 1: /* AFE - write byte */
+ ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, reg->val, 1);
+ break;
+ case 2: /* Video Block - write byte */
+ ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, reg->val, 1);
+ break;
+ case 3: /* I2S block - write byte */
+ ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, reg->val, 1);
+ break;
+ case 4: /* AFE - write dword */
+ ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, reg->val, 4);
+ break;
+ case 5: /* Video Block - write dword */
+ ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, reg->val, 4);
break;
+ case 6: /* I2S block - write dword */
+ ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, reg->val, 4);
+ break;
+ default:
+ return -EINVAL;
}
-
- call_all(dev, core, s_register, reg);
-
- return ret;
+ return ret < 0 ? ret : 0;
}
#endif
@@ -2208,8 +2002,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_tuner = cx231xx_s_tuner,
.vidioc_g_frequency = cx231xx_g_frequency,
.vidioc_s_frequency = cx231xx_s_frequency,
- .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = cx231xx_g_chip_info,
.vidioc_g_register = cx231xx_g_register,
.vidioc_s_register = cx231xx_s_register,
#endif
@@ -2240,8 +2034,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_tuner = radio_s_tuner,
.vidioc_g_frequency = cx231xx_g_frequency,
.vidioc_s_frequency = cx231xx_s_frequency,
- .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = cx231xx_g_chip_info,
.vidioc_g_register = cx231xx_g_register,
.vidioc_s_register = cx231xx_s_register,
#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 5ad9fd61d3c8..e812119ea7a8 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -945,7 +945,7 @@ int cx231xx_enum_input(struct file *file, void *priv,
struct v4l2_input *i);
int cx231xx_g_input(struct file *file, void *priv, unsigned int *i);
int cx231xx_s_input(struct file *file, void *priv, unsigned int i);
-int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
+int cx231xx_g_chip_info(struct file *file, void *fh, struct v4l2_dbg_chip_info *chip);
int cx231xx_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg);
int cx231xx_s_register(struct file *file, void *priv,
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index b638fc1cd574..1ea17dc2a76e 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -55,7 +55,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
- __func__, req->wlen, req->rlen);
+ KBUILD_MODNAME, req->wlen, req->rlen);
ret = -EINVAL;
goto exit;
}
@@ -91,9 +91,10 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
checksum = af9035_checksum(state->buf, rlen - 2);
tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1];
if (tmp_checksum != checksum) {
- dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
- "(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
- tmp_checksum, checksum);
+ dev_err(&d->udev->dev,
+ "%s: command=%02x checksum mismatch (%04x != %04x)\n",
+ KBUILD_MODNAME, req->cmd, tmp_checksum,
+ checksum);
ret = -EIO;
goto exit;
}
@@ -268,11 +269,29 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
memcpy(&buf[5], msg[0].buf, msg[0].len);
ret = af9035_ctrl_msg(d, &req);
}
+ } else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+ if (msg[0].len > 40) {
+ /* TODO: correct limits > 40 */
+ ret = -EOPNOTSUPP;
+ } else {
+ /* I2C */
+ u8 buf[5];
+ struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+ buf, msg[0].len, msg[0].buf };
+ req.mbox |= ((msg[0].addr & 0x80) >> 3);
+ buf[0] = msg[0].len;
+ buf[1] = msg[0].addr << 1;
+ buf[2] = 0x00; /* reg addr len */
+ buf[3] = 0x00; /* reg addr MSB */
+ buf[4] = 0x00; /* reg addr LSB */
+ ret = af9035_ctrl_msg(d, &req);
+ }
} else {
/*
- * We support only two kind of I2C transactions:
- * 1) 1 x read + 1 x write
+ * We support only three kind of I2C transactions:
+ * 1) 1 x read + 1 x write (repeated start)
* 2) 1 x write
+ * 3) 1 x read
*/
ret = -EOPNOTSUPP;
}
@@ -317,8 +336,8 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
dev_info(&d->udev->dev,
"%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n",
- __func__, state->prechip_version, state->chip_version,
- state->chip_type);
+ KBUILD_MODNAME, state->prechip_version,
+ state->chip_version, state->chip_type);
if (state->chip_type == 0x9135) {
if (state->chip_version == 0x02)
@@ -382,9 +401,10 @@ static int af9035_download_firmware_old(struct dvb_usb_device *d,
hdr_checksum = fw->data[fw->size - i + 5] << 8;
hdr_checksum |= fw->data[fw->size - i + 6] << 0;
- dev_dbg(&d->udev->dev, "%s: core=%d addr=%04x data_len=%d " \
- "checksum=%04x\n", __func__, hdr_core, hdr_addr,
- hdr_data_len, hdr_checksum);
+ dev_dbg(&d->udev->dev,
+ "%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+ __func__, hdr_core, hdr_addr, hdr_data_len,
+ hdr_checksum);
if (((hdr_core != 1) && (hdr_core != 2)) ||
(hdr_data_len > i)) {
@@ -489,7 +509,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
u8 rbuf[4];
u8 tmp;
struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf };
dev_dbg(&d->udev->dev, "%s:\n", __func__);
/*
@@ -498,11 +518,11 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
* which is done by master demod.
* Master feeds also clock and controls power via GPIO.
*/
- ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
if (ret < 0)
goto err;
- if (tmp) {
+ if (tmp == 1 || tmp == 3) {
/* configure gpioh1, reset & power slave demod */
ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
if (ret < 0)
@@ -620,13 +640,15 @@ static int af9035_read_config(struct dvb_usb_device *d)
}
/* check if there is dual tuners */
- ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
if (ret < 0)
goto err;
- state->dual_mode = tmp;
- dev_dbg(&d->udev->dev, "%s: dual mode=%d\n", __func__,
- state->dual_mode);
+ if (tmp == 1 || tmp == 3)
+ state->dual_mode = true;
+
+ dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", __func__,
+ tmp, state->dual_mode);
if (state->dual_mode) {
/* read 2nd demodulator I2C address */
@@ -1200,9 +1222,9 @@ static int af9035_init(struct dvb_usb_device *d)
{ 0x80f9a4, 0x00, 0x01 },
};
- dev_dbg(&d->udev->dev, "%s: USB speed=%d frame_size=%04x " \
- "packet_size=%02x\n", __func__,
- d->udev->speed, frame_size, packet_size);
+ dev_dbg(&d->udev->dev,
+ "%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+ __func__, d->udev->speed, frame_size, packet_size);
/* init endpoints */
for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -1477,7 +1499,7 @@ static const struct usb_device_id af9035_id_table[] = {
&af9035_props, "AVerMedia Twinstar (A825)", NULL) },
{ DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS,
&af9035_props, "Asus U3100Mini Plus", NULL) },
- { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
&af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
/* IT9135 devices */
#if 0
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index b5827ca3a01e..a1c68d829b8c 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -100,8 +100,13 @@ static const u32 clock_lut_it9135[] = {
* eeprom is memory mapped as read only. Writing that memory mapped address
* will not corrupt eeprom.
*
- * eeprom has value 0x00 single mode and 0x03 for dual mode as far as I have
- * seen to this day.
+ * TS mode:
+ * 0 TS
+ * 1 DCA + PIP
+ * 3 PIP
+ * n DCA
+ *
+ * Values 0 and 3 are seen to this day. 0 for single TS and 3 for dual TS.
*/
#define EEPROM_BASE_AF9035 0x42fd
@@ -109,7 +114,7 @@ static const u32 clock_lut_it9135[] = {
#define EEPROM_SHIFT 0x10
#define EEPROM_IR_MODE 0x10
-#define EEPROM_DUAL_MODE 0x29
+#define EEPROM_TS_MODE 0x29
#define EEPROM_2ND_DEMOD_ADDR 0x2a
#define EEPROM_IR_TYPE 0x2c
#define EEPROM_1_IF_L 0x30
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 658c6d47fdff..399916bd588f 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -140,7 +140,7 @@ struct dvb_usb_rc {
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
int (*query) (struct dvb_usb_device *d);
unsigned int interval;
- const enum rc_driver_type driver_type;
+ enum rc_driver_type driver_type;
bool bulk_mode;
};
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
index e48cdeb9df41..1cb6899cf797 100644
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
static int dvb_usb_it913x_firmware;
module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set firmware 0=auto"\
+MODULE_PARM_DESC(firmware, "set firmware 0=auto "\
"1=IT9137 2=IT9135 V1 3=IT9135 V2");
#define FW_IT9137 "dvb-usb-it9137-01.fw"
#define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
@@ -796,6 +796,9 @@ static const struct usb_device_id it913x_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
&it913x_properties, "Avermedia A835B(4835)",
RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
+ &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2",
+ RC_MAP_IT913X_V1) },
{} /* Terminating entry */
};
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
index ef4c65fcbb73..879c529640f7 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -31,8 +31,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
if (mxl111sf_tuner_debug) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
-#define err pr_err
-
/* ------------------------------------------------------------------------ */
struct mxl111sf_tuner_state {
@@ -113,7 +111,7 @@ static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
filt_bw = 63;
break;
default:
- err("%s: invalid bandwidth setting!", __func__);
+ pr_err("%s: invalid bandwidth setting!", __func__);
return NULL;
}
@@ -304,12 +302,12 @@ static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
bw = 8;
break;
default:
- err("%s: bandwidth not set!", __func__);
+ pr_err("%s: bandwidth not set!", __func__);
return -EINVAL;
}
break;
default:
- err("%s: modulation type not supported!", __func__);
+ pr_err("%s: modulation type not supported!", __func__);
return -EINVAL;
}
ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index efdcb15358f1..e97964ef7f56 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -52,12 +52,6 @@ MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define deb_info pr_debug
-#define deb_reg pr_debug
-#define deb_adv pr_debug
-#define err pr_err
-#define info pr_info
-
int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
@@ -65,7 +59,7 @@ int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
int ret;
u8 sndbuf[1+wlen];
- deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+ pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
memset(sndbuf, 0, 1+wlen);
@@ -98,12 +92,12 @@ int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
if (buf[0] == addr)
*data = buf[1];
else {
- err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+ pr_err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
addr, buf[0], buf[1]);
ret = -EINVAL;
}
- deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+ pr_debug("R: (0x%02x, 0x%02x)\n", addr, *data);
fail:
return ret;
}
@@ -113,11 +107,11 @@ int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
u8 buf[] = { addr, data };
int ret;
- deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+ pr_debug("W: (0x%02x, 0x%02x)\n", addr, data);
ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
if (mxl_fail(ret))
- err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+ pr_err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
return ret;
}
@@ -134,7 +128,7 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
#if 1
/* dont know why this usually errors out on the first try */
if (mxl_fail(ret))
- err("error writing addr: 0x%02x, mask: 0x%02x, "
+ pr_err("error writing addr: 0x%02x, mask: 0x%02x, "
"data: 0x%02x, retrying...", addr, mask, data);
ret = mxl111sf_read_reg(state, addr, &val);
@@ -167,7 +161,7 @@ int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
ctrl_reg_info[i].mask,
ctrl_reg_info[i].data);
if (mxl_fail(ret)) {
- err("failed on reg #%d (0x%02x)", i,
+ pr_err("failed on reg #%d (0x%02x)", i,
ctrl_reg_info[i].addr);
break;
}
@@ -225,7 +219,7 @@ static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
mxl_rev = "UNKNOWN REVISION";
break;
}
- info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+ pr_info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
fail:
return ret;
}
@@ -239,7 +233,7 @@ fail:
" on first probe attempt"); \
___ret = mxl1x1sf_get_chip_info(state); \
if (mxl_fail(___ret)) \
- err("failed to get chip info during probe"); \
+ pr_err("failed to get chip info during probe"); \
else \
mxl_debug("probe needed a retry " \
"in order to succeed."); \
@@ -270,14 +264,14 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
goto fail;
}
- deb_info("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
mutex_lock(&state->fe_lock);
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
err = mxl1x1sf_soft_reset(state);
mxl_fail(err);
@@ -326,7 +320,7 @@ static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
goto fail;
}
- deb_info("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
@@ -344,7 +338,7 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff)
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
int ret = 0;
- deb_info("%s(%d)\n", __func__, onoff);
+ pr_debug("%s(%d)\n", __func__, onoff);
if (onoff) {
ret = mxl111sf_enable_usb_output(state);
@@ -368,7 +362,7 @@ static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff)
struct mxl111sf_state *state = fe_to_priv(fe);
int ret = 0;
- deb_info("%s(%d)\n", __func__, onoff);
+ pr_debug("%s(%d)\n", __func__, onoff);
if (onoff) {
ret = mxl111sf_enable_usb_output(state);
@@ -394,7 +388,7 @@ static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff)
struct mxl111sf_state *state = fe_to_priv(fe);
int ret = 0;
- deb_info("%s(%d)\n", __func__, onoff);
+ pr_debug("%s(%d)\n", __func__, onoff);
if (onoff) {
ret = mxl111sf_enable_usb_output(state);
@@ -424,7 +418,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
int ret;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
@@ -432,7 +426,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
adap_state->gpio_mode = state->gpio_mode;
@@ -495,7 +489,7 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
int ret;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
@@ -503,7 +497,7 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_MH;
adap_state->gpio_mode = state->gpio_mode;
@@ -580,7 +574,7 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
int ret;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
@@ -588,7 +582,7 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_MH;
adap_state->gpio_mode = state->gpio_mode;
@@ -667,7 +661,7 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
int ret;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
@@ -675,7 +669,7 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_MH;
adap_state->gpio_mode = state->gpio_mode;
@@ -742,7 +736,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
int ret;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
@@ -750,7 +744,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
+ pr_err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
adap_state->gpio_mode = state->gpio_mode;
@@ -802,7 +796,7 @@ static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
}
#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
- err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+ pr_err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
__func__, __LINE__, \
(ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
pwr0, pwr1, pwr2, pwr3)
@@ -868,7 +862,7 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
struct mxl111sf_state *state = adap_to_priv(adap);
int i;
- deb_adv("%s()\n", __func__);
+ pr_debug("%s()\n", __func__);
for (i = 0; i < state->num_frontends; i++) {
if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state,
@@ -902,7 +896,7 @@ static int mxl111sf_init(struct dvb_usb_device *d)
ret = get_chip_info(state);
if (mxl_fail(ret))
- err("failed to get chip info during probe");
+ pr_err("failed to get chip info during probe");
mutex_init(&state->fe_lock);
@@ -950,7 +944,7 @@ static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap)
static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
{
int ret;
- deb_info("%s\n", __func__);
+ pr_debug("%s\n", __func__);
ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
if (ret < 0)
@@ -970,7 +964,7 @@ static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
{
int ret;
- deb_info("%s\n", __func__);
+ pr_debug("%s\n", __func__);
ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
if (ret < 0)
@@ -990,7 +984,7 @@ static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
{
int ret;
- deb_info("%s\n", __func__);
+ pr_debug("%s\n", __func__);
ret = mxl111sf_attach_demod(adap, 0);
if (ret < 0)
@@ -1006,7 +1000,7 @@ static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint)
{
- deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint);
+ pr_debug("%s: endpoint=%d size=8192\n", __func__, endpoint);
stream->type = USB_BULK;
stream->count = 5;
stream->endpoint = endpoint;
@@ -1016,7 +1010,7 @@ static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *strea
static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream,
u8 endpoint, int framesperurb, int framesize)
{
- deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint,
+ pr_debug("%s: endpoint=%d size=%d\n", __func__, endpoint,
framesperurb * framesize);
stream->type = USB_ISOC;
stream->count = 5;
@@ -1035,7 +1029,7 @@ static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *strea
static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
*ts_type = DVB_USB_FE_TS_TYPE_188;
if (dvb_usb_mxl111sf_isoc)
@@ -1076,7 +1070,7 @@ static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
*ts_type = DVB_USB_FE_TS_TYPE_188;
if (dvb_usb_mxl111sf_isoc)
@@ -1117,7 +1111,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc = {
static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
*ts_type = DVB_USB_FE_TS_TYPE_RAW;
if (dvb_usb_mxl111sf_isoc)
@@ -1158,7 +1152,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mh = {
static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
if (fe->id == 0) {
*ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1184,7 +1178,7 @@ static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff)
{
- deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+ pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
if (fe->id == 0)
return mxl111sf_ep6_streaming_ctrl(fe, onoff);
@@ -1228,7 +1222,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
if (fe->id == 0) {
*ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1260,7 +1254,7 @@ static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff)
{
- deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+ pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
if (fe->id == 0)
return mxl111sf_ep6_streaming_ctrl(fe, onoff);
@@ -1306,7 +1300,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury = {
static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
u8 *ts_type, struct usb_data_stream_properties *stream)
{
- deb_info("%s: fe=%d\n", __func__, fe->id);
+ pr_debug("%s: fe=%d\n", __func__, fe->id);
if (fe->id == 0) {
*ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1332,7 +1326,7 @@ static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff)
{
- deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+ pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
if (fe->id == 0)
return mxl111sf_ep4_streaming_ctrl(fe, onoff);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 2cc8ec70e3b6..c0cd0848631b 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1041,67 +1041,34 @@ err:
static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
- u8 val;
dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
if (onoff) {
- /* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+ /* GPIO3=1, GPIO4=0 */
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18);
if (ret)
goto err;
- val |= 0x08;
- val &= 0xef;
-
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ /* suspend? */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10);
if (ret)
goto err;
- /* demod_ctl_1 */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+ /* enable PLL */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80);
if (ret)
goto err;
- val &= 0xef;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
- if (ret)
- goto err;
-
- /* demod control */
- /* PLL enable */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- /* bit 7 to 1 */
- val |= 0x80;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- if (ret)
- goto err;
-
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- val |= 0x20;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ /* disable reset */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20);
if (ret)
goto err;
mdelay(5);
- /*enable ADC_Q and ADC_I */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- val |= 0x48;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ /* enable ADC */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x48, 0x48);
if (ret)
goto err;
@@ -1114,36 +1081,18 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
if (ret)
goto err;
} else {
- /* demod_ctl_1 */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
- if (ret)
- goto err;
-
- val |= 0x0c;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
- if (ret)
- goto err;
-
- /* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
- if (ret)
- goto err;
-
- val |= 0x10;
-
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ /* GPIO4=1 */
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10);
if (ret)
goto err;
- /* demod control */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ /* disable ADC */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x48);
if (ret)
goto err;
- val &= 0x37;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ /* disable PLL */
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
if (ret)
goto err;
@@ -1242,42 +1191,47 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
return 0;
}
-#else
- #define rtl2831u_get_rc_config NULL
-#endif
-#if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2832u_rc_query(struct dvb_usb_device *d)
{
- int ret, i;
+ int ret, i, len;
struct rtl28xxu_priv *priv = d->priv;
+ struct ir_raw_event ev;
u8 buf[128];
- int len;
- struct rtl28xxu_reg_val rc_nec_tab[] = {
- { IR_RX_CTRL, 0x20 },
- { IR_RX_BUF_CTRL, 0x80 },
- { IR_RX_IF, 0xff },
- { IR_RX_IE, 0xff },
- { IR_MAX_DURATION0, 0xd0 },
- { IR_MAX_DURATION1, 0x07 },
- { IR_IDLE_LEN0, 0xc0 },
- { IR_IDLE_LEN1, 0x00 },
- { IR_GLITCH_LEN, 0x03 },
- { IR_RX_CLK, 0x09 },
- { IR_RX_CFG, 0x1c },
- { IR_MAX_H_TOL_LEN, 0x1e },
- { IR_MAX_L_TOL_LEN, 0x1e },
- { IR_RX_CTRL, 0x80 },
+ static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
+ {IR_RX_IF, 0x03, 0xff},
+ {IR_RX_BUF_CTRL, 0x80, 0xff},
+ {IR_RX_CTRL, 0x80, 0xff},
};
/* init remote controller */
if (!priv->rc_active) {
- for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
- ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
- rc_nec_tab[i].val);
+ static const struct rtl28xxu_reg_val_mask init_tab[] = {
+ {SYS_DEMOD_CTL1, 0x00, 0x04},
+ {SYS_DEMOD_CTL1, 0x00, 0x08},
+ {USB_CTRL, 0x20, 0x20},
+ {SYS_GPIO_DIR, 0x00, 0x08},
+ {SYS_GPIO_OUT_EN, 0x08, 0x08},
+ {SYS_GPIO_OUT_VAL, 0x08, 0x08},
+ {IR_MAX_DURATION0, 0xd0, 0xff},
+ {IR_MAX_DURATION1, 0x07, 0xff},
+ {IR_IDLE_LEN0, 0xc0, 0xff},
+ {IR_IDLE_LEN1, 0x00, 0xff},
+ {IR_GLITCH_LEN, 0x03, 0xff},
+ {IR_RX_CLK, 0x09, 0xff},
+ {IR_RX_CFG, 0x1c, 0xff},
+ {IR_MAX_H_TOL_LEN, 0x1e, 0xff},
+ {IR_MAX_L_TOL_LEN, 0x1e, 0xff},
+ {IR_RX_CTRL, 0x80, 0xff},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_tab); i++) {
+ ret = rtl28xx_wr_reg_mask(d, init_tab[i].reg,
+ init_tab[i].val, init_tab[i].mask);
if (ret)
goto err;
}
+
priv->rc_active = true;
}
@@ -1293,14 +1247,32 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
goto err;
len = buf[0];
+
+ /* read raw code from hw */
ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+ if (ret)
+ goto err;
- /* TODO: pass raw IR to Kernel IR decoder */
+ /* let hw receive new code */
+ for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
+ ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg,
+ refresh_tab[i].val, refresh_tab[i].mask);
+ if (ret)
+ goto err;
+ }
- ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
- ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
- ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
+ /* pass data to Kernel IR decoder */
+ init_ir_raw_event(&ev);
+ for (i = 0; i < len; i++) {
+ ev.pulse = buf[i] >> 7;
+ ev.duration = 50800 * (buf[i] & 0x7f);
+ ir_raw_event_store_with_filter(d->rc_dev, &ev);
+ }
+
+ /* 'flush' ir_raw_event_store_with_filter() */
+ ir_raw_event_set_idle(d->rc_dev, true);
+ ir_raw_event_handle(d->rc_dev);
exit:
return ret;
err:
@@ -1311,15 +1283,19 @@ err:
static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
struct dvb_usb_rc *rc)
{
- rc->map_name = RC_MAP_EMPTY;
- rc->allowed_protos = RC_BIT_NEC;
+ /* load empty to enable rc */
+ if (!rc->map_name)
+ rc->map_name = RC_MAP_EMPTY;
+ rc->allowed_protos = RC_BIT_ALL;
+ rc->driver_type = RC_DRIVER_IR_RAW;
rc->query = rtl2832u_rc_query;
rc->interval = 400;
return 0;
}
#else
- #define rtl2832u_get_rc_config NULL
+#define rtl2831u_get_rc_config NULL
+#define rtl2832u_get_rc_config NULL
#endif
static const struct dvb_usb_device_properties rtl2831u_props = {
@@ -1379,7 +1355,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
&rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
- &rtl2832u_props, "TerraTec Cinergy T Stick Black", NULL) },
+ &rtl2832u_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
&rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
@@ -1403,11 +1379,15 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393,
&rtl2832u_props, "GIGABYTE U7300", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104,
- &rtl2832u_props, "Digivox Micro Hd", NULL) },
+ &rtl2832u_props, "MSI DIGIVOX Micro HD", NULL) },
{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
&rtl2832u_props, "Compro VideoMate U620F", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
&rtl2832u_props, "MaxMedia HU394-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
+ &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
+ &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 533a33127289..729b3540c2f9 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -97,6 +97,12 @@ struct rtl28xxu_reg_val {
u8 val;
};
+struct rtl28xxu_reg_val_mask {
+ u16 reg;
+ u8 val;
+ u8 mask;
+};
+
/*
* memory map
*
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index 91e0119e8a87..ea2d5ee86576 100644
--- a/drivers/media/usb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -264,7 +264,7 @@ struct stb0899_config az6027_stb0899_config = {
.demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */
.xtal_freq = 27000000,
- .inversion = IQ_SWAP_ON, /* 1 */
+ .inversion = IQ_SWAP_ON,
.lo_clk = 76500000,
.hi_clk = 99000000,
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index d1ddfa13de86..449a99605a87 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -828,7 +828,7 @@ static struct stb0899_config stb0899_config = {
.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
.xtal_freq = 27000000, /* Assume Hz ? */
- .inversion = IQ_SWAP_ON, /* ? */
+ .inversion = IQ_SWAP_ON,
.lo_clk = 76500000,
.hi_clk = 99000000,
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 83bfbe4c980f..dc65742c4bbc 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -37,7 +37,6 @@
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
#include "em28xx.h"
@@ -83,26 +82,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev);
/* Reset for the most [analog] boards */
static struct em28xx_reg_seq default_analog[] = {
- {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Reset for the most [digital] boards */
static struct em28xx_reg_seq default_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 analog */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
- {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10},
{0x05, 0xff, 0x10, 10},
{ -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 digital */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
- {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x04, 0x0f, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
{ -1, -1, -1, -1},
@@ -110,14 +109,14 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
/* Board Hauppauge WinTV HVR 900 (R2) digital */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
- {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
{ -1, -1, -1, -1},
};
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
- {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
@@ -128,11 +127,11 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
/* Board - EM2882 Kworld 315U digital */
static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM28XX_R08_GPIO, 0xfe, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
{EM2880_R04_GPO, 0x04, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 10},
- {EM28XX_R08_GPIO, 0x7e, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0x7e, 0xff, 10},
{ -1, -1, -1, -1},
};
@@ -145,13 +144,13 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
};
static struct em28xx_reg_seq kworld_330u_analog[] = {
- {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq kworld_330u_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
@@ -163,12 +162,12 @@ static struct em28xx_reg_seq kworld_330u_digital[] = {
GOP3 - s5h1409 reset
*/
static struct em28xx_reg_seq evga_indtube_analog[] = {
- {EM28XX_R08_GPIO, 0x79, 0xff, 60},
+ {EM2820_R08_GPIO_CTRL, 0x79, 0xff, 60},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq evga_indtube_digital[] = {
- {EM28XX_R08_GPIO, 0x7a, 0xff, 1},
+ {EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1},
{EM2880_R04_GPO, 0x04, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 1},
{ -1, -1, -1, -1},
@@ -186,31 +185,31 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
* EM_GPIO_7 - currently unknown
*/
static struct em28xx_reg_seq kworld_a340_digital[] = {
- {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Pinnacle Hybrid Pro eb1a:2881 */
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
- {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */
{EM2880_R04_GPO, 0x0c, 0xff, 1},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
- {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
@@ -219,66 +218,66 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
GPIO4 - CU1216L NIM
Other GPIOs seems to be don't care. */
static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
- {EM28XX_R08_GPIO, 0xfe, 0xff, 10},
- {EM28XX_R08_GPIO, 0xde, 0xff, 10},
- {EM28XX_R08_GPIO, 0xfe, 0xff, 10},
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM28XX_R08_GPIO, 0x7f, 0xff, 10},
- {EM28XX_R08_GPIO, 0x6f, 0xff, 10},
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xde, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0x7f, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6f, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{-1, -1, -1, -1},
};
/* Callback for the most boards */
static struct em28xx_reg_seq default_tuner_gpio[] = {
- {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
- {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
- {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Mute/unmute */
static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
- {EM28XX_R08_GPIO, 5, 7, 10},
+ {EM2820_R08_GPIO_CTRL, 5, 7, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
- {EM28XX_R08_GPIO, 4, 7, 10},
+ {EM2820_R08_GPIO_CTRL, 4, 7, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq compro_mute_gpio[] = {
- {EM28XX_R08_GPIO, 6, 7, 10},
+ {EM2820_R08_GPIO_CTRL, 6, 7, 10},
{ -1, -1, -1, -1},
};
/* Terratec AV350 */
static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
- {EM28XX_R08_GPIO, 0xff, 0x7f, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0x7f, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq silvercrest_reg_seq[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM28XX_R08_GPIO, 0x01, 0xf7, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2820_R08_GPIO_CTRL, 0x01, 0xf7, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq vc211a_enable[] = {
- {EM28XX_R08_GPIO, 0xff, 0x07, 10},
- {EM28XX_R08_GPIO, 0xff, 0x0f, 10},
- {EM28XX_R08_GPIO, 0xff, 0x0b, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0x07, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0x0f, 10},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0x0b, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq dikom_dk300_digital[] = {
- {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
@@ -286,14 +285,14 @@ static struct em28xx_reg_seq dikom_dk300_digital[] = {
/* Reset for the most [digital] boards */
static struct em28xx_reg_seq leadership_digital[] = {
- {EM2874_R80_GPIO, 0x70, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq leadership_reset[] = {
- {EM2874_R80_GPIO, 0xf0, 0xff, 10},
- {EM2874_R80_GPIO, 0xb0, 0xff, 10},
- {EM2874_R80_GPIO, 0xf0, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
{ -1, -1, -1, -1},
};
@@ -302,25 +301,25 @@ static struct em28xx_reg_seq leadership_reset[] = {
* GPIO_7 - LED
*/
static struct em28xx_reg_seq pctv_290e[] = {
- {EM2874_R80_GPIO, 0x00, 0xff, 80},
- {EM2874_R80_GPIO, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
- {EM2874_R80_GPIO, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80},
+ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
{-1, -1, -1, -1},
};
#if 0
static struct em28xx_reg_seq terratec_h5_gpio[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xf6, 0xff, 100},
- {EM2874_R80_GPIO, 0xf2, 0xff, 50},
- {EM2874_R80_GPIO, 0xf6, 0xff, 50},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_h5_digital[] = {
- {EM2874_R80_GPIO, 0xf6, 0xff, 10},
- {EM2874_R80_GPIO, 0xe6, 0xff, 100},
- {EM2874_R80_GPIO, 0xa6, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
{ -1, -1, -1, -1},
};
#endif
@@ -336,51 +335,52 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
* GPIO_7 - LED (green LED)
*/
static struct em28xx_reg_seq pctv_460e[] = {
- {EM2874_R80_GPIO, 0x01, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50},
{0x0d, 0xff, 0xff, 50},
- {EM2874_R80_GPIO, 0x41, 0xff, 50}, /* GPIO_6=1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */
{0x0d, 0x42, 0xff, 50},
- {EM2874_R80_GPIO, 0x61, 0xff, 50}, /* GPIO_5=1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff, 50}, /* GPIO_5=1 */
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
- {EM2874_R80_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xfd, 0xff, 10}, /* xc5000 reset */
- {EM2874_R80_GPIO, 0xf9, 0xff, 35},
- {EM2874_R80_GPIO, 0xfd, 0xff, 10},
- {EM2874_R80_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xfe, 0xff, 10},
- {EM2874_R80_GPIO, 0xbe, 0xff, 10},
- {EM2874_R80_GPIO, 0xfe, 0xff, 20},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10}, /* xc5000 reset */
+ {EM2874_R80_GPIO_P0_CTRL, 0xf9, 0xff, 35},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 20},
{ -1, -1, -1, -1},
};
#if 0
static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
- {EM2874_R80_GPIO, 0x6f, 0xff, 10},
- {EM2874_R80_GPIO, 0x4f, 0xff, 10}, /* xc5000 reset */
- {EM2874_R80_GPIO, 0x6f, 0xff, 10},
- {EM2874_R80_GPIO, 0x4f, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */
+ {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10},
{ -1, -1, -1, -1},
};
static struct em28xx_reg_seq hauppauge_930c_digital[] = {
- {EM2874_R80_GPIO, 0xf6, 0xff, 10},
- {EM2874_R80_GPIO, 0xe6, 0xff, 100},
- {EM2874_R80_GPIO, 0xa6, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
{ -1, -1, -1, -1},
};
#endif
/* 1b80:e425 MaxMedia UB425-TC
+ * 1b80:e1cc Delock 61959
* GPIO_6 - demod reset, 0=active
* GPIO_7 - LED, 0=active
*/
static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
- {EM2874_R80_GPIO, 0x83, 0xff, 100},
- {EM2874_R80_GPIO, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
- {EM2874_R80_GPIO, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
{-1, -1, -1, -1},
};
@@ -391,9 +391,9 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
* GPIO_7: LED, 1=active
*/
static struct em28xx_reg_seq pctv_510e[] = {
- {EM2874_R80_GPIO, 0x10, 0xff, 100},
- {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
- {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
{ -1, -1, -1, -1},
};
@@ -404,10 +404,10 @@ static struct em28xx_reg_seq pctv_510e[] = {
* GPIO_7: LED, 1=active
*/
static struct em28xx_reg_seq pctv_520e[] = {
- {EM2874_R80_GPIO, 0x10, 0xff, 100},
- {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
- {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
- {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
{ -1, -1, -1, -1},
};
@@ -2017,6 +2017,19 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
+ /* 1b80:e1cc Delock 61959
+ * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
+ * mostly the same as MaxMedia UB-425-TC but different remote */
+ [EM2874_BOARD_DELOCK_61959] = {
+ .name = "Delock 61959",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = maxmedia_ub425_tc,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_DELOCK_61959,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -2178,6 +2191,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2884_BOARD_PCTV_510E },
{ USB_DEVICE(0x2013, 0x0251),
.driver_info = EM2884_BOARD_PCTV_520E },
+ { USB_DEVICE(0x1b80, 0xe1cc),
+ .driver_info = EM2874_BOARD_DELOCK_61959 },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2284,9 +2299,9 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
break;
case EM2861_BOARD_KWORLD_PVRTV_300U:
case EM2880_BOARD_KWORLD_DVB_305U:
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x6d);
msleep(10);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x7d);
msleep(10);
break;
case EM2870_BOARD_COMPRO_VIDEOMATE:
@@ -2296,45 +2311,45 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
msleep(10);
em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
msleep(10);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xdc);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc);
mdelay(70);
break;
case EM2870_BOARD_TERRATEC_XS_MT2060:
/* this device needs some gpio writes to get the DVB-T
demod work */
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
break;
case EM2870_BOARD_PINNACLE_PCTV_DVB:
/* this device needs some gpio writes to get the
DVB-T demod work */
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
mdelay(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
break;
case EM2820_BOARD_GADMEI_UTV310:
case EM2820_BOARD_MSI_VOX_USB_2:
/* enables audio for that devices */
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
break;
case EM2882_BOARD_KWORLD_ATSC_315U:
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
msleep(10);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
msleep(10);
em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
msleep(10);
@@ -2360,13 +2375,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
break;
case EM2820_BOARD_IODATA_GVMVP_SZ:
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
msleep(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
msleep(10);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
msleep(70);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
msleep(70);
break;
}
@@ -2653,7 +2668,7 @@ static void em28xx_card_setup(struct em28xx *dev)
dev->tuner_type = tv.tuner_type;
- if (tv.audio_processor == V4L2_IDENT_MSPX4XX) {
+ if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) {
dev->i2s_speed = 2048000;
dev->board.has_msp34xx = 1;
}
@@ -2662,12 +2677,12 @@ static void em28xx_card_setup(struct em28xx *dev)
case EM2882_BOARD_KWORLD_ATSC_315U:
em28xx_write_reg(dev, 0x0d, 0x42);
msleep(10);
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
msleep(10);
break;
case EM2820_BOARD_KWORLD_PVRTV2800RF:
/* GPIO enables sound on KWORLD PVR TV 2800RF */
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
+ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf9);
break;
case EM2820_BOARD_UNKNOWN:
case EM2800_BOARD_UNKNOWN:
@@ -2881,10 +2896,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
em28xx_set_model(dev);
- /* Set the default GPO/GPIO for legacy devices */
- dev->reg_gpo_num = EM2880_R04_GPO;
- dev->reg_gpio_num = EM28XX_R08_GPIO;
-
dev->wait_after_write = 5;
/* Based on the Chip ID, set the device configuration */
@@ -2932,13 +2943,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
break;
case CHIP_ID_EM2874:
chip_name = "em2874";
- dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
case CHIP_ID_EM28174:
chip_name = "em28174";
- dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
@@ -2948,7 +2957,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
break;
case CHIP_ID_EM2884:
chip_name = "em2884";
- dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
@@ -2977,11 +2985,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return 0;
}
- /* Prepopulate cached GPO register content */
- retval = em28xx_read_reg(dev, dev->reg_gpo_num);
- if (retval >= 0)
- dev->reg_gpo = retval;
-
em28xx_pre_card_setup(dev);
if (!dev->board.is_em2800) {
@@ -3071,7 +3074,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (dev->board.has_msp34xx) {
/* Send a reset to other chips via gpio */
- retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+ retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
if (retval < 0) {
em28xx_errdev("%s: em28xx_write_reg - "
"msp34xx(1) failed! error [%d]\n",
@@ -3080,7 +3083,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
}
msleep(3);
- retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
if (retval < 0) {
em28xx_errdev("%s: em28xx_write_reg - "
"msp34xx(2) failed! error [%d]\n",
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index a802128ce9c5..fc157af5234a 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -193,23 +193,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
{
- int rc;
-
- rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
-
- /* Stores GPO/GPIO values at the cache, if changed
- Only write values should be stored, since input on a GPIO
- register will return the input bits.
- Not sure what happens on reading GPO register.
- */
- if (rc >= 0) {
- if (reg == dev->reg_gpo_num)
- dev->reg_gpo = buf[0];
- else if (reg == dev->reg_gpio_num)
- dev->reg_gpio = buf[0];
- }
-
- return rc;
+ return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
}
EXPORT_SYMBOL_GPL(em28xx_write_regs);
@@ -231,14 +215,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
int oldval;
u8 newval;
- /* Uses cache for gpo/gpio registers */
- if (reg == dev->reg_gpo_num)
- oldval = dev->reg_gpo;
- else if (reg == dev->reg_gpio_num)
- oldval = dev->reg_gpio;
- else
- oldval = em28xx_read_reg(dev, reg);
-
+ oldval = em28xx_read_reg(dev, reg);
if (oldval < 0)
return oldval;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index b22f8fed8127..bb1e8dca80cd 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -421,23 +421,23 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
int i;
struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
- {EM2874_R80_GPIO, 0xff, 0xff, 0x65},
- {EM2874_R80_GPIO, 0xfb, 0xff, 0x32},
- {EM2874_R80_GPIO, 0xff, 0xff, 0xb8},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0x65},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfb, 0xff, 0x32},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0xb8},
{ -1, -1, -1, -1},
};
struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
- {EM2874_R80_GPIO, 0xef, 0xff, 0x01},
- {EM2874_R80_GPIO, 0xaf, 0xff, 0x65},
- {EM2874_R80_GPIO, 0xef, 0xff, 0x76},
- {EM2874_R80_GPIO, 0xef, 0xff, 0x01},
- {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b},
- {EM2874_R80_GPIO, 0xef, 0xff, 0x40},
-
- {EM2874_R80_GPIO, 0xcf, 0xff, 0x65},
- {EM2874_R80_GPIO, 0xef, 0xff, 0x65},
- {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b},
- {EM2874_R80_GPIO, 0xef, 0xff, 0x65},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x01},
+ {EM2874_R80_GPIO_P0_CTRL, 0xaf, 0xff, 0x65},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x76},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x01},
+ {EM2874_R80_GPIO_P0_CTRL, 0xcf, 0xff, 0x0b},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x40},
+
+ {EM2874_R80_GPIO_P0_CTRL, 0xcf, 0xff, 0x65},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x65},
+ {EM2874_R80_GPIO_P0_CTRL, 0xcf, 0xff, 0x0b},
+ {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x65},
{ -1, -1, -1, -1},
};
@@ -487,16 +487,16 @@ static void terratec_h5_init(struct em28xx *dev)
{
int i;
struct em28xx_reg_seq terratec_h5_init[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xf6, 0xff, 100},
- {EM2874_R80_GPIO, 0xf2, 0xff, 50},
- {EM2874_R80_GPIO, 0xf6, 0xff, 100},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{ -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_h5_end[] = {
- {EM2874_R80_GPIO, 0xe6, 0xff, 100},
- {EM2874_R80_GPIO, 0xa6, 0xff, 50},
- {EM2874_R80_GPIO, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{ -1, -1, -1, -1},
};
struct {
@@ -543,15 +543,15 @@ static void terratec_htc_stick_init(struct em28xx *dev)
* 0xb6: unknown (does not affect DVB-T).
*/
struct em28xx_reg_seq terratec_htc_stick_init[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xf6, 0xff, 100},
- {EM2874_R80_GPIO, 0xe6, 0xff, 50},
- {EM2874_R80_GPIO, 0xf6, 0xff, 100},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{ -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_htc_stick_end[] = {
- {EM2874_R80_GPIO, 0xb6, 0xff, 100},
- {EM2874_R80_GPIO, 0xf6, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50},
{ -1, -1, -1, -1},
};
@@ -590,16 +590,16 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
int i;
struct em28xx_reg_seq terratec_htc_usb_xs_init[] = {
- {EM28XX_R08_GPIO, 0xff, 0xff, 10},
- {EM2874_R80_GPIO, 0xb2, 0xff, 100},
- {EM2874_R80_GPIO, 0xb2, 0xff, 50},
- {EM2874_R80_GPIO, 0xb6, 0xff, 100},
+ {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100},
{ -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_htc_usb_xs_end[] = {
- {EM2874_R80_GPIO, 0xa6, 0xff, 100},
- {EM2874_R80_GPIO, 0xa6, 0xff, 50},
- {EM2874_R80_GPIO, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{ -1, -1, -1, -1},
};
@@ -1216,6 +1216,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_a8293_config);
break;
+ case EM2874_BOARD_DELOCK_61959:
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
@@ -1235,8 +1236,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
}
/* TODO: we need drx-3913k firmware in order to support DVB-T */
- em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
- "driver version\n");
+ em28xx_info("MaxMedia UB425-TC/Delock 61959: only DVB-C " \
+ "supported by that driver version\n");
break;
case EM2884_BOARD_PCTV_510E:
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 466b19d0d767..ea181e4b68c5 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -32,7 +32,6 @@
#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
#define EM28XX_SBUTTON_QUERY_INTERVAL 500
-#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 622871db04aa..0e0477847965 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -49,8 +49,9 @@
/* GPIO/GPO registers */
-#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
-#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
+#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
+#define EM2820_R08_GPIO_CTRL 0x08 /* em2820-em2873/83 only */
+#define EM2820_R09_GPIO_STATE 0x09 /* em2820-em2873/83 only */
#define EM28XX_R06_I2C_CLK 0x06
@@ -67,7 +68,8 @@
#define EM28XX_R0A_CHIPID 0x0a
-#define EM28XX_R0C_USBSUSP 0x0c /* */
+#define EM28XX_R0C_USBSUSP 0x0c
+#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 /* 1=button pressed, needs reset */
#define EM28XX_R0E_AUDIOSRC 0x0e
#define EM28XX_R0F_XCLK 0x0f
@@ -193,7 +195,20 @@
#define EM2874_R50_IR_CONFIG 0x50
#define EM2874_R51_IR 0x51
#define EM2874_R5F_TS_ENABLE 0x5f
-#define EM2874_R80_GPIO 0x80
+
+/* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */
+/*
+ * NOTE: not all ports are bonded out;
+ * Some ports are multiplexed with special function I/O
+ */
+#define EM2874_R80_GPIO_P0_CTRL 0x80
+#define EM2874_R81_GPIO_P1_CTRL 0x81
+#define EM2874_R82_GPIO_P2_CTRL 0x82
+#define EM2874_R83_GPIO_P3_CTRL 0x83
+#define EM2874_R84_GPIO_P0_STATE 0x84
+#define EM2874_R85_GPIO_P1_STATE 0x85
+#define EM2874_R86_GPIO_P2_STATE 0x86
+#define EM2874_R87_GPIO_P3_STATE 0x87
/* em2874 IR config register (0x50) */
#define EM2874_IR_NEC 0x00
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 32d60e5546bc..1a577ed8ea0c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -41,7 +41,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -1309,28 +1308,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_BRIDGE) {
- if (chip->match.addr > 1)
- return -EINVAL;
- return 0;
- }
- if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
- chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_chip_info(struct file *file, void *priv,
struct v4l2_dbg_chip_info *chip)
@@ -1366,14 +1343,9 @@ static int vidioc_g_register(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
int ret;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_BRIDGE:
- if (reg->match.addr > 1)
- return -EINVAL;
- if (!reg->match.addr)
- break;
- /* fall-through */
- case V4L2_CHIP_MATCH_AC97:
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (reg->match.addr) {
ret = em28xx_read_ac97(dev, reg->reg);
if (ret < 0)
return ret;
@@ -1381,15 +1353,6 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
reg->size = 1;
return 0;
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- return -EINVAL;
}
/* Match host */
@@ -1421,25 +1384,10 @@ static int vidioc_s_register(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
__le16 buf;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_BRIDGE:
- if (reg->match.addr > 1)
- return -EINVAL;
- if (!reg->match.addr)
- break;
- /* fall-through */
- case V4L2_CHIP_MATCH_AC97:
- return em28xx_write_ac97(dev, reg->reg, reg->val);
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
+ if (reg->match.addr > 1)
return -EINVAL;
- }
+ if (reg->match.addr)
+ return em28xx_write_ac97(dev, reg->reg, reg->val);
/* Match host */
buf = cpu_to_le16(reg->val);
@@ -1795,7 +1743,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
@@ -1826,7 +1773,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index a9323b63d8e5..205e9038b1c0 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -130,6 +130,7 @@
#define EM2884_BOARD_PCTV_520E 86
#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87
#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
+#define EM2874_BOARD_DELOCK_61959 89
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -636,12 +637,6 @@ struct em28xx {
enum em28xx_mode mode;
- /* register numbers for GPO/GPIO registers */
- u16 reg_gpo_num, reg_gpio_num;
-
- /* Caches GPO and GPIO registers */
- unsigned char reg_gpo, reg_gpio;
-
/* Snapshot button */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 5995ec4de6bc..b7ae8721b847 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1029,33 +1029,35 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+static int vidioc_g_chip_info(struct file *file, void *priv,
+ struct v4l2_dbg_chip_info *chip)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
gspca_dev->usb_err = 0;
- return gspca_dev->sd_desc->get_register(gspca_dev, reg);
+ if (gspca_dev->sd_desc->get_chip_info)
+ return gspca_dev->sd_desc->get_chip_info(gspca_dev, chip);
+ return chip->match.addr ? -EINVAL : 0;
}
-static int vidioc_s_register(struct file *file, void *priv,
- const struct v4l2_dbg_register *reg)
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
gspca_dev->usb_err = 0;
- return gspca_dev->sd_desc->set_register(gspca_dev, reg);
+ return gspca_dev->sd_desc->get_register(gspca_dev, reg);
}
-#endif
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
+static int vidioc_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
gspca_dev->usb_err = 0;
- return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
+ return gspca_dev->sd_desc->set_register(gspca_dev, reg);
}
+#endif
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmtdesc)
@@ -1974,10 +1976,10 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -2086,14 +2088,10 @@ int gspca_dev_probe2(struct usb_interface *intf,
v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF);
v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF);
v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF);
- if (!gspca_dev->sd_desc->get_chip_ident)
- v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_CHIP_IDENT);
#ifdef CONFIG_VIDEO_ADV_DEBUG
- if (!gspca_dev->sd_desc->get_chip_ident ||
- !gspca_dev->sd_desc->get_register)
+ if (!gspca_dev->sd_desc->get_register)
v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_REGISTER);
- if (!gspca_dev->sd_desc->get_chip_ident ||
- !gspca_dev->sd_desc->set_register)
+ if (!gspca_dev->sd_desc->set_register)
v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_S_REGISTER);
#endif
if (!gspca_dev->sd_desc->get_jcomp)
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index ef8efeb80070..ac0b11f46f50 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -78,8 +78,8 @@ typedef int (*cam_get_reg_op) (struct gspca_dev *,
struct v4l2_dbg_register *);
typedef int (*cam_set_reg_op) (struct gspca_dev *,
const struct v4l2_dbg_register *);
-typedef int (*cam_ident_op) (struct gspca_dev *,
- struct v4l2_dbg_chip_ident *);
+typedef int (*cam_chip_info_op) (struct gspca_dev *,
+ struct v4l2_dbg_chip_info *);
typedef void (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
@@ -112,8 +112,8 @@ struct sd_desc {
#ifdef CONFIG_VIDEO_ADV_DEBUG
cam_set_reg_op set_register;
cam_get_reg_op get_register;
+ cam_chip_info_op get_chip_info;
#endif
- cam_ident_op get_chip_ident;
#if IS_ENABLED(CONFIG_INPUT)
cam_int_pkt_op int_pkt_scan;
/* other_input makes the gspca core create gspca_dev->input even when
diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index 6008c8d546a3..a91509643563 100644
--- a/drivers/media/usb/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
@@ -93,7 +93,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
-#include <media/v4l2-chip-ident.h>
#include "gspca.h"
/* Include pac common sof detection functions */
#include "pac_common.h"
@@ -849,8 +848,7 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
* long on the USB bus)
*/
- if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
- reg->match.addr == 0 &&
+ if (reg->match.addr == 0 &&
(reg->reg < 0x000000ff) &&
(reg->val <= 0x000000ff)
) {
@@ -871,20 +869,6 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
}
return gspca_dev->usb_err;
}
-
-static int sd_chip_ident(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_chip_ident *chip)
-{
- int ret = -EINVAL;
-
- if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
- chip->match.addr == 0) {
- chip->revision = 0;
- chip->ident = V4L2_IDENT_UNKNOWN;
- ret = 0;
- }
- return ret;
-}
#endif
#if IS_ENABLED(CONFIG_INPUT)
@@ -931,7 +915,6 @@ static const struct sd_desc sd_desc = {
.dq_callback = do_autogain,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.set_register = sd_dbg_s_register,
- .get_chip_ident = sd_chip_ident,
#endif
#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index ead9a1f58513..f4453d52801b 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -27,7 +27,6 @@
#include "gspca.h"
#include "jpeg.h"
-#include <media/v4l2-chip-ident.h>
#include <linux/dmi.h>
MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
@@ -582,22 +581,6 @@ static const s16 hsv_blue_y[] = {
4, 2, 0, -1, -3, -5, -7, -9, -11
};
-static const u16 i2c_ident[] = {
- V4L2_IDENT_OV9650,
- V4L2_IDENT_OV9655,
- V4L2_IDENT_SOI968,
- V4L2_IDENT_OV7660,
- V4L2_IDENT_OV7670,
- V4L2_IDENT_MT9V011,
- V4L2_IDENT_MT9V111,
- V4L2_IDENT_MT9V112,
- V4L2_IDENT_MT9M001C12ST,
- V4L2_IDENT_MT9M111,
- V4L2_IDENT_MT9M112,
- V4L2_IDENT_HV7131R,
-[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
-};
-
static const u16 bridge_init[][2] = {
{0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
{0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
@@ -1574,21 +1557,19 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- if (reg->match.addr != 0)
- return -EINVAL;
+ reg->size = 1;
+ switch (reg->match.addr) {
+ case 0:
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
reg_r(gspca_dev, reg->reg, 1);
reg->val = gspca_dev->usb_buf[0];
return gspca_dev->usb_err;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- if (reg->match.addr != sd->i2c_addr)
- return -EINVAL;
+ case 1:
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
+ reg->size = 2;
} else {
i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
}
@@ -1602,17 +1583,13 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- if (reg->match.addr != 0)
- return -EINVAL;
+ switch (reg->match.addr) {
+ case 0:
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
reg_w1(gspca_dev, reg->reg, reg->val);
return gspca_dev->usb_err;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- if (reg->match.addr != sd->i2c_addr)
- return -EINVAL;
+ case 1:
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
i2c_w2(gspca_dev, reg->reg, reg->val);
@@ -1623,29 +1600,17 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
}
return -EINVAL;
}
-#endif
-static int sd_chip_ident(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_chip_ident *chip)
+static int sd_chip_info(struct gspca_dev *gspca_dev,
+ struct v4l2_dbg_chip_info *chip)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
- switch (chip->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- if (chip->match.addr != 0)
- return -EINVAL;
- chip->revision = 0;
- chip->ident = V4L2_IDENT_SN9C20X;
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- if (chip->match.addr != sd->i2c_addr)
- return -EINVAL;
- chip->revision = 0;
- chip->ident = i2c_ident[sd->sensor];
- return 0;
- }
- return -EINVAL;
+ if (chip->match.addr > 1)
+ return -EINVAL;
+ if (chip->match.addr == 1)
+ strlcpy(chip->name, "sensor", sizeof(chip->name));
+ return 0;
}
+#endif
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -2356,8 +2321,8 @@ static const struct sd_desc sd_desc = {
#ifdef CONFIG_VIDEO_ADV_DEBUG
.set_register = sd_dbg_s_register,
.get_register = sd_dbg_g_register,
+ .get_chip_info = sd_chip_info,
#endif
- .get_chip_ident = sd_chip_ident,
};
#define SN9C20X(sensor, i2c_addr, flags) \
diff --git a/drivers/media/usb/hdpvr/Kconfig b/drivers/media/usb/hdpvr/Kconfig
index de247f3c7d05..d73d9a1952b4 100644
--- a/drivers/media/usb/hdpvr/Kconfig
+++ b/drivers/media/usb/hdpvr/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_HDPVR
tristate "Hauppauge HD PVR support"
- depends on VIDEO_DEV
+ depends on VIDEO_DEV && VIDEO_V4L2
---help---
This is a video4linux driver for Hauppauge's HD PVR USB device.
diff --git a/drivers/media/usb/hdpvr/hdpvr-control.c b/drivers/media/usb/hdpvr/hdpvr-control.c
index ae8f229d1141..6053661dc04b 100644
--- a/drivers/media/usb/hdpvr/hdpvr-control.c
+++ b/drivers/media/usb/hdpvr/hdpvr-control.c
@@ -45,20 +45,11 @@ int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
return ret < 0 ? ret : 0;
}
-struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
+int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
{
- struct hdpvr_video_info *vidinf = NULL;
-#ifdef HDPVR_DEBUG
- char print_buf[15];
-#endif
int ret;
- vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
- if (!vidinf) {
- v4l2_err(&dev->v4l2_dev, "out of memory\n");
- goto err;
- }
-
+ vidinf->valid = false;
mutex_lock(&dev->usbc_mutex);
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
@@ -66,14 +57,10 @@ struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
0x1400, 0x0003,
dev->usbc_buf, 5,
1000);
- if (ret == 5) {
- vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
- vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
- vidinf->fps = dev->usbc_buf[4];
- }
#ifdef HDPVR_DEBUG
if (hdpvr_debug & MSG_INFO) {
+ char print_buf[15];
hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
sizeof(print_buf), 0);
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
@@ -82,12 +69,15 @@ struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
#endif
mutex_unlock(&dev->usbc_mutex);
- if (!vidinf->width || !vidinf->height || !vidinf->fps) {
- kfree(vidinf);
- vidinf = NULL;
- }
-err:
- return vidinf;
+ if (ret < 0)
+ return ret;
+
+ vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+ vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
+ vidinf->fps = dev->usbc_buf[4];
+ vidinf->valid = vidinf->width && vidinf->height && vidinf->fps;
+
+ return 0;
}
int get_input_lines_info(struct hdpvr_device *dev)
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 8247c19d6260..cb694055ba7d 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -220,7 +220,6 @@ static int hdpvr_device_init(struct hdpvr_device *dev)
{
int ret;
u8 *buf;
- struct hdpvr_video_info *vidinf;
if (device_authorization(dev))
return -EACCES;
@@ -242,13 +241,6 @@ static int hdpvr_device_init(struct hdpvr_device *dev)
"control request returned %d\n", ret);
mutex_unlock(&dev->usbc_mutex);
- vidinf = get_video_info(dev);
- if (!vidinf)
- v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
- "no valid video signal or device init failed\n");
- else
- kfree(vidinf);
-
/* enable fan and bling leds */
mutex_lock(&dev->usbc_mutex);
buf[0] = 0x1;
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 774ba0e820be..4f8567aa99d8 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -277,44 +277,50 @@ error:
static int hdpvr_start_streaming(struct hdpvr_device *dev)
{
int ret;
- struct hdpvr_video_info *vidinf;
+ struct hdpvr_video_info vidinf;
if (dev->status == STATUS_STREAMING)
return 0;
- else if (dev->status != STATUS_IDLE)
+ if (dev->status != STATUS_IDLE)
return -EAGAIN;
- vidinf = get_video_info(dev);
+ ret = get_video_info(dev, &vidinf);
+ if (ret < 0)
+ return ret;
- if (vidinf) {
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
- "video signal: %dx%d@%dhz\n", vidinf->width,
- vidinf->height, vidinf->fps);
- kfree(vidinf);
-
- /* start streaming 2 request */
- ret = usb_control_msg(dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- 0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
- "encoder start control request returned %d\n", ret);
+ if (!vidinf.valid) {
+ msleep(250);
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "no video signal at input %d\n", dev->options.video_input);
+ return -EAGAIN;
+ }
- hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "video signal: %dx%d@%dhz\n", vidinf.width,
+ vidinf.height, vidinf.fps);
- dev->status = STATUS_STREAMING;
+ /* start streaming 2 request */
+ ret = usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ 0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "encoder start control request returned %d\n", ret);
+ if (ret < 0)
+ return ret;
- INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
- queue_work(dev->workqueue, &dev->worker);
+ ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+ if (ret)
+ return ret;
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
- "streaming started\n");
+ dev->status = STATUS_STREAMING;
- return 0;
- }
- msleep(250);
- v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
- "no video signal at input %d\n", dev->options.video_input);
- return -EAGAIN;
+ INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+ queue_work(dev->workqueue, &dev->worker);
+
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "streaming started\n");
+
+ return 0;
}
@@ -606,22 +612,20 @@ static int vidioc_g_std(struct file *file, void *_fh,
static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
{
struct hdpvr_device *dev = video_drvdata(file);
- struct hdpvr_video_info *vid_info;
+ struct hdpvr_video_info vid_info;
struct hdpvr_fh *fh = _fh;
+ int ret;
- *a = V4L2_STD_ALL;
+ *a = V4L2_STD_UNKNOWN;
if (dev->options.video_input == HDPVR_COMPONENT)
return fh->legacy_mode ? 0 : -ENODATA;
- vid_info = get_video_info(dev);
- if (vid_info == NULL)
- return 0;
- if (vid_info->width == 720 &&
- (vid_info->height == 480 || vid_info->height == 576)) {
- *a = (vid_info->height == 480) ?
+ ret = get_video_info(dev, &vid_info);
+ if (vid_info.valid && vid_info.width == 720 &&
+ (vid_info.height == 480 || vid_info.height == 576)) {
+ *a = (vid_info.height == 480) ?
V4L2_STD_525_60 : V4L2_STD_625_50;
}
- kfree(vid_info);
- return 0;
+ return ret;
}
static int vidioc_s_dv_timings(struct file *file, void *_fh,
@@ -665,7 +669,7 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
{
struct hdpvr_device *dev = video_drvdata(file);
struct hdpvr_fh *fh = _fh;
- struct hdpvr_video_info *vid_info;
+ struct hdpvr_video_info vid_info;
bool interlaced;
int ret = 0;
int i;
@@ -673,10 +677,12 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
fh->legacy_mode = false;
if (dev->options.video_input)
return -ENODATA;
- vid_info = get_video_info(dev);
- if (vid_info == NULL)
+ ret = get_video_info(dev, &vid_info);
+ if (ret)
+ return ret;
+ if (!vid_info.valid)
return -ENOLCK;
- interlaced = vid_info->fps <= 30;
+ interlaced = vid_info.fps <= 30;
for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
unsigned hsize;
@@ -688,17 +694,17 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch +
bt->height;
fps = (unsigned)bt->pixelclock / (hsize * vsize);
- if (bt->width != vid_info->width ||
- bt->height != vid_info->height ||
+ if (bt->width != vid_info.width ||
+ bt->height != vid_info.height ||
bt->interlaced != interlaced ||
- (fps != vid_info->fps && fps + 1 != vid_info->fps))
+ (fps != vid_info.fps && fps + 1 != vid_info.fps))
continue;
*timings = hdpvr_dv_timings[i];
break;
}
if (i == ARRAY_SIZE(hdpvr_dv_timings))
ret = -ERANGE;
- kfree(vid_info);
+
return ret;
}
@@ -988,6 +994,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
{
struct hdpvr_device *dev = video_drvdata(file);
struct hdpvr_fh *fh = _fh;
+ int ret;
/*
* The original driver would always returns the current detected
@@ -1000,14 +1007,15 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
* last set format.
*/
if (fh->legacy_mode) {
- struct hdpvr_video_info *vid_info;
+ struct hdpvr_video_info vid_info;
- vid_info = get_video_info(dev);
- if (!vid_info)
+ ret = get_video_info(dev, &vid_info);
+ if (ret < 0)
+ return ret;
+ if (!vid_info.valid)
return -EFAULT;
- f->fmt.pix.width = vid_info->width;
- f->fmt.pix.height = vid_info->height;
- kfree(vid_info);
+ f->fmt.pix.width = vid_info.width;
+ f->fmt.pix.height = vid_info.height;
} else {
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index 1478f3d57630..dc685d44cb3e 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -154,6 +154,7 @@ struct hdpvr_video_info {
u16 width;
u16 height;
u8 fps;
+ bool valid;
};
enum {
@@ -303,7 +304,7 @@ int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
int hdpvr_config_call(struct hdpvr_device *dev, uint value,
unsigned char valbuf);
-struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
+int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vid_info);
/* :0 s b8 81 1800 0003 0003 3 < */
/* :0 0 3 = 0301ff */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index e11267f35d87..c4d51d78f837 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2704,6 +2704,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
pvr2_hdw_render_useless(hdw);
}
+void pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *hdw, struct video_device *vdev)
+{
+ vdev->v4l2_dev = &hdw->v4l2_dev;
+}
/* Destroy hardware interaction structure */
void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
@@ -5162,41 +5166,3 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
} while(0); LOCK_GIVE(hdw->ctl_lock);
return result;
}
-
-
-int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- const struct v4l2_dbg_match *match, u64 reg_id,
- int setFl, u64 *val_ptr)
-{
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct v4l2_dbg_register req;
- int stat = 0;
- int okFl = 0;
-
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-
- req.match = *match;
- req.reg = reg_id;
- if (setFl) req.val = *val_ptr;
- /* It would be nice to know if a sub-device answered the request */
- v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
- if (!setFl) *val_ptr = req.val;
- if (okFl) {
- return stat;
- }
- return -EINVAL;
-#else
- return -ENOSYS;
-#endif
-}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
index 91bae930cd79..41847076f51a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
@@ -22,6 +22,7 @@
#include <linux/usb.h>
#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
#include "pvrusb2-io.h"
#include "pvrusb2-ctrl.h"
@@ -138,6 +139,9 @@ const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *);
/* Called when hardware has been unplugged */
void pvr2_hdw_disconnect(struct pvr2_hdw *);
+/* Sets v4l2_dev of a video_device struct */
+void pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *, struct video_device *);
+
/* Get the number of defined controls */
unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
@@ -234,15 +238,6 @@ int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
enum pvr2_v4l_type index,int);
-/* Direct read/write access to chip's registers:
- match - specify criteria to identify target chip (this is a v4l dbg struct)
- reg_id - register number to access
- setFl - true to set the register, false to read it
- val_ptr - storage location for source / result. */
-int pvr2_hdw_register_access(struct pvr2_hdw *,
- const struct v4l2_dbg_match *match, u64 reg_id,
- int setFl, u64 *val_ptr);
-
/* The following entry points are all lower level things you normally don't
want to worry about. */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 20b6ae0bb40d..1e354747de3f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -354,9 +354,9 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
if (scnt < sp->buffer_slot_count) {
struct pvr2_buffer **nb = NULL;
if (scnt) {
- nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+ nb = kmemdup(sp->buffers, scnt * sizeof(*nb),
+ GFP_KERNEL);
if (!nb) return -ENOMEM;
- memcpy(nb,sp->buffers,scnt * sizeof(*nb));
}
kfree(sp->buffers);
sp->buffers = nb;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index a8a65fa57930..7c280f35eea9 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -31,6 +31,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -800,36 +801,6 @@ static int pvr2_log_status(struct file *file, void *priv)
return 0;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
-{
- struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- u64 val;
- int ret;
-
- ret = pvr2_hdw_register_access(
- hdw, &req->match, req->reg,
- 0, &val);
- req->val = val;
- return ret;
-}
-
-static int pvr2_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *req)
-{
- struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- u64 val;
- int ret;
-
- val = req->val;
- ret = pvr2_hdw_register_access(
- hdw, &req->match, req->reg,
- 1, &val);
- return ret;
-}
-#endif
-
static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
.vidioc_querycap = pvr2_querycap,
.vidioc_g_priority = pvr2_g_priority,
@@ -864,10 +835,6 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
.vidioc_g_ext_ctrls = pvr2_g_ext_ctrls,
.vidioc_s_ext_ctrls = pvr2_s_ext_ctrls,
.vidioc_try_ext_ctrls = pvr2_try_ext_ctrls,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = pvr2_g_register,
- .vidioc_s_register = pvr2_s_register,
-#endif
};
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
@@ -904,8 +871,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
{
if (!dip) return;
- if (!dip->devbase.parent) return;
- dip->devbase.parent = NULL;
+ if (!dip->devbase.v4l2_dev->dev) return;
+ dip->devbase.v4l2_dev->dev = NULL;
device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
}
@@ -1298,7 +1265,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *vp,
int v4l_type)
{
- struct usb_device *usbdev;
int mindevnum;
int unit_number;
struct pvr2_hdw *hdw;
@@ -1306,7 +1272,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->v4lp = vp;
hdw = vp->channel.mc_head->hdw;
- usbdev = pvr2_hdw_get_dev(hdw);
dip->v4l_type = v4l_type;
switch (v4l_type) {
case VFL_TYPE_GRABBER:
@@ -1355,7 +1320,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
mindevnum = nr_ptr[unit_number];
}
- dip->devbase.parent = &usbdev->dev;
+ pvr2_hdw_set_v4l2_dev(hdw, &dip->devbase);
if ((video_register_device(&dip->devbase,
dip->v4l_type, mindevnum) < 0) &&
(video_register_device(&dip->devbase,
diff --git a/drivers/media/usb/sn9c102/sn9c102.h b/drivers/media/usb/sn9c102/sn9c102.h
index 2bc153e869be..8a917f060503 100644
--- a/drivers/media/usb/sn9c102/sn9c102.h
+++ b/drivers/media/usb/sn9c102/sn9c102.h
@@ -25,6 +25,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -100,6 +101,8 @@ static DECLARE_RWSEM(sn9c102_dev_lock);
struct sn9c102_device {
struct video_device* v4ldev;
+ struct v4l2_device v4l2_dev;
+
enum sn9c102_bridge bridge;
struct sn9c102_sensor sensor;
diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c
index c957e9aa6077..2cb44de2b92c 100644
--- a/drivers/media/usb/sn9c102/sn9c102_core.c
+++ b/drivers/media/usb/sn9c102/sn9c102_core.c
@@ -1737,6 +1737,7 @@ static void sn9c102_release_resources(struct kref *kref)
video_device_node_name(cam->v4ldev));
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ v4l2_device_unregister(&cam->v4l2_dev);
usb_put_dev(cam->usbdev);
kfree(cam->control_buffer);
kfree(cam);
@@ -3254,6 +3255,13 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->usbdev = udev;
+ /* register v4l2_device early so it can be used for printks */
+ if (v4l2_device_register(&intf->dev, &cam->v4l2_dev)) {
+ dev_err(&intf->dev, "v4l2_device_register failed\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+
if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
DBG(1, "kzalloc() failed");
err = -ENOMEM;
@@ -3325,7 +3333,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
cam->v4ldev->fops = &sn9c102_fops;
cam->v4ldev->release = video_device_release;
- cam->v4ldev->parent = &udev->dev;
+ cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
init_completion(&cam->probe);
@@ -3377,6 +3385,7 @@ fail:
kfree(cam->control_buffer);
if (cam->v4ldev)
video_device_release(cam->v4ldev);
+ v4l2_device_unregister(&cam->v4l2_dev);
kfree(cam);
}
return err;
@@ -3407,6 +3416,8 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
wake_up_interruptible_all(&cam->wait_open);
+ v4l2_device_disconnect(&cam->v4l2_dev);
+
kref_put(&cam->kref, sn9c102_release_resources);
up_write(&sn9c102_dev_lock);
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index a59153d2f8bf..876fc26565e3 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -31,7 +31,6 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
#include <media/videobuf2-vmalloc.h>
#include <media/saa7115.h>
@@ -454,19 +453,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- switch (chip->match.type) {
- case V4L2_CHIP_MATCH_BRIDGE:
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -475,19 +461,6 @@ static int vidioc_g_register(struct file *file, void *priv,
int rc;
u8 val;
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
/* Match host */
rc = stk1160_read_reg(dev, reg->reg, &val);
reg->val = val;
@@ -501,19 +474,6 @@ static int vidioc_s_register(struct file *file, void *priv,
{
struct stk1160 *dev = video_drvdata(file);
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
/* Match host */
return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val));
}
@@ -543,7 +503,6 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = {
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 307d8c5fb7cd..1ccaaddaa307 100644
--- a/drivers/media/usb/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -1114,7 +1114,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
/* Default values for STD and resolutions */
dev->width = 720;
dev->height = 480;
- dev->norm = V4L2_STD_PAL_M;
+ dev->norm = V4L2_STD_NTSC_M;
/* Configure tuner */
tm6000_config_tuner(dev);
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index a78de1d1bc9e..cc1aa14996ff 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1076,6 +1076,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ *norm = dev->norm;
+ return 0;
+}
+
static const char *iname[] = {
[TM6000_INPUT_TV] = "Television",
[TM6000_INPUT_COMPOSITE1] = "Composite 1",
@@ -1134,7 +1143,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
dev->input = i;
- rc = vidioc_s_std(file, priv, dev->vfd->current_norm);
+ rc = vidioc_s_std(file, priv, dev->norm);
return rc;
}
@@ -1547,6 +1556,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1570,7 +1580,6 @@ static struct video_device tm6000_template = {
.ioctl_ops = &video_ioctl_ops,
.release = video_device_release,
.tvnorms = TM6000_STD,
- .current_norm = V4L2_STD_NTSC_M,
};
static const struct v4l2_file_operations radio_fops = {
diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index 21b9049c7b3f..f8a60c197534 100644
--- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
@@ -1768,6 +1768,8 @@ err_i2c_del_adapter:
i2c_del_adapter(&ttusb->i2c_adap);
err_unregister_adapter:
dvb_unregister_adapter (&ttusb->adapter);
+ ttusb_free_iso_urbs(ttusb);
+ kfree(ttusb);
return result;
}
diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig
new file mode 100644
index 000000000000..8864436464bf
--- /dev/null
+++ b/drivers/media/usb/usbtv/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_USBTV
+ tristate "USBTV007 video capture support"
+ depends on VIDEO_DEV
+ select VIDEOBUF2_VMALLOC
+
+ ---help---
+ This is a video4linux2 driver for USBTV007 based video capture devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbtv
diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile
new file mode 100644
index 000000000000..28b872fa94e1
--- /dev/null
+++ b/drivers/media/usb/usbtv/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c
new file mode 100644
index 000000000000..bf43f874685e
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv.c
@@ -0,0 +1,696 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Following LWN articles were very useful in construction of this driver:
+ * Video4Linux2 API series: http://lwn.net/Articles/203924/
+ * videobuf2 API explanation: http://lwn.net/Articles/447435/
+ * Thanks go to Jonathan Corbet for providing this quality documentation.
+ * He is awesome.
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * 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. The name of the author may not 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").
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* Hardware. */
+#define USBTV_VIDEO_ENDP 0x81
+#define USBTV_BASE 0xc000
+#define USBTV_REQUEST_REG 12
+
+/* Number of concurrent isochronous urbs submitted.
+ * Higher numbers was seen to overly saturate the USB bus. */
+#define USBTV_ISOC_TRANSFERS 16
+#define USBTV_ISOC_PACKETS 8
+
+#define USBTV_WIDTH 720
+#define USBTV_HEIGHT 480
+
+#define USBTV_CHUNK_SIZE 256
+#define USBTV_CHUNK 240
+#define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \
+ / 2 / USBTV_CHUNK)
+
+/* Chunk header. */
+#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
+ == 0x88000000)
+#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
+#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
+#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
+
+/* A single videobuf2 frame buffer. */
+struct usbtv_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+/* Per-device structure. */
+struct usbtv {
+ struct device *dev;
+ struct usb_device *udev;
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct vb2_queue vb2q;
+ struct mutex v4l2_lock;
+ struct mutex vb2q_lock;
+
+ /* List of videobuf2 buffers protected by a lock. */
+ spinlock_t buflock;
+ struct list_head bufs;
+
+ /* Number of currently processed frame, useful find
+ * out when a new one begins. */
+ u32 frame_id;
+
+ int iso_size;
+ unsigned int sequence;
+ struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+};
+
+static int usbtv_setup_capture(struct usbtv *usbtv)
+{
+ int ret;
+ int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
+ int i;
+ static const u16 protoregs[][2] = {
+ /* These seem to enable the device. */
+ { USBTV_BASE + 0x0008, 0x0001 },
+ { USBTV_BASE + 0x01d0, 0x00ff },
+ { USBTV_BASE + 0x01d9, 0x0002 },
+
+ /* These seem to influence color parameters, such as
+ * brightness, etc. */
+ { USBTV_BASE + 0x0239, 0x0040 },
+ { USBTV_BASE + 0x0240, 0x0000 },
+ { USBTV_BASE + 0x0241, 0x0000 },
+ { USBTV_BASE + 0x0242, 0x0002 },
+ { USBTV_BASE + 0x0243, 0x0080 },
+ { USBTV_BASE + 0x0244, 0x0012 },
+ { USBTV_BASE + 0x0245, 0x0090 },
+ { USBTV_BASE + 0x0246, 0x0000 },
+
+ { USBTV_BASE + 0x0278, 0x002d },
+ { USBTV_BASE + 0x0279, 0x000a },
+ { USBTV_BASE + 0x027a, 0x0032 },
+ { 0xf890, 0x000c },
+ { 0xf894, 0x0086 },
+
+ { USBTV_BASE + 0x00ac, 0x00c0 },
+ { USBTV_BASE + 0x00ad, 0x0000 },
+ { USBTV_BASE + 0x00a2, 0x0012 },
+ { USBTV_BASE + 0x00a3, 0x00e0 },
+ { USBTV_BASE + 0x00a4, 0x0028 },
+ { USBTV_BASE + 0x00a5, 0x0082 },
+ { USBTV_BASE + 0x00a7, 0x0080 },
+ { USBTV_BASE + 0x0000, 0x0014 },
+ { USBTV_BASE + 0x0006, 0x0003 },
+ { USBTV_BASE + 0x0090, 0x0099 },
+ { USBTV_BASE + 0x0091, 0x0090 },
+ { USBTV_BASE + 0x0094, 0x0068 },
+ { USBTV_BASE + 0x0095, 0x0070 },
+ { USBTV_BASE + 0x009c, 0x0030 },
+ { USBTV_BASE + 0x009d, 0x00c0 },
+ { USBTV_BASE + 0x009e, 0x00e0 },
+ { USBTV_BASE + 0x0019, 0x0006 },
+ { USBTV_BASE + 0x008c, 0x00ba },
+ { USBTV_BASE + 0x0101, 0x00ff },
+ { USBTV_BASE + 0x010c, 0x00b3 },
+ { USBTV_BASE + 0x01b2, 0x0080 },
+ { USBTV_BASE + 0x01b4, 0x00a0 },
+ { USBTV_BASE + 0x014c, 0x00ff },
+ { USBTV_BASE + 0x014d, 0x00ca },
+ { USBTV_BASE + 0x0113, 0x0053 },
+ { USBTV_BASE + 0x0119, 0x008a },
+ { USBTV_BASE + 0x013c, 0x0003 },
+ { USBTV_BASE + 0x0150, 0x009c },
+ { USBTV_BASE + 0x0151, 0x0071 },
+ { USBTV_BASE + 0x0152, 0x00c6 },
+ { USBTV_BASE + 0x0153, 0x0084 },
+ { USBTV_BASE + 0x0154, 0x00bc },
+ { USBTV_BASE + 0x0155, 0x00a0 },
+ { USBTV_BASE + 0x0156, 0x00a0 },
+ { USBTV_BASE + 0x0157, 0x009c },
+ { USBTV_BASE + 0x0158, 0x001f },
+ { USBTV_BASE + 0x0159, 0x0006 },
+ { USBTV_BASE + 0x015d, 0x0000 },
+
+ { USBTV_BASE + 0x0284, 0x0088 },
+ { USBTV_BASE + 0x0003, 0x0004 },
+ { USBTV_BASE + 0x001a, 0x0079 },
+ { USBTV_BASE + 0x0100, 0x00d3 },
+ { USBTV_BASE + 0x010e, 0x0068 },
+ { USBTV_BASE + 0x010f, 0x009c },
+ { USBTV_BASE + 0x0112, 0x00f0 },
+ { USBTV_BASE + 0x0115, 0x0015 },
+ { USBTV_BASE + 0x0117, 0x0000 },
+ { USBTV_BASE + 0x0118, 0x00fc },
+ { USBTV_BASE + 0x012d, 0x0004 },
+ { USBTV_BASE + 0x012f, 0x0008 },
+ { USBTV_BASE + 0x0220, 0x002e },
+ { USBTV_BASE + 0x0225, 0x0008 },
+ { USBTV_BASE + 0x024e, 0x0002 },
+ { USBTV_BASE + 0x024f, 0x0001 },
+ { USBTV_BASE + 0x0254, 0x005f },
+ { USBTV_BASE + 0x025a, 0x0012 },
+ { USBTV_BASE + 0x025b, 0x0001 },
+ { USBTV_BASE + 0x0263, 0x001c },
+ { USBTV_BASE + 0x0266, 0x0011 },
+ { USBTV_BASE + 0x0267, 0x0005 },
+ { USBTV_BASE + 0x024e, 0x0002 },
+ { USBTV_BASE + 0x024f, 0x0002 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(protoregs); i++) {
+ u16 index = protoregs[i][0];
+ u16 value = protoregs[i][1];
+
+ ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Called for each 256-byte image chunk.
+ * First word identifies the chunk, followed by 240 words of image
+ * data and padding. */
+static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
+{
+ int frame_id, odd, chunk_no;
+ u32 *frame;
+ struct usbtv_buf *buf;
+ unsigned long flags;
+
+ /* Ignore corrupted lines. */
+ if (!USBTV_MAGIC_OK(chunk))
+ return;
+ frame_id = USBTV_FRAME_ID(chunk);
+ odd = USBTV_ODD(chunk);
+ chunk_no = USBTV_CHUNK_NO(chunk);
+
+ /* Deinterlace. TODO: Use interlaced frame format. */
+ chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3;
+ chunk_no += !odd * 3;
+
+ if (chunk_no >= USBTV_CHUNKS)
+ return;
+
+ /* Beginning of a frame. */
+ if (chunk_no == 0)
+ usbtv->frame_id = frame_id;
+
+ spin_lock_irqsave(&usbtv->buflock, flags);
+ if (list_empty(&usbtv->bufs)) {
+ /* No free buffers. Userspace likely too slow. */
+ spin_unlock_irqrestore(&usbtv->buflock, flags);
+ return;
+ }
+
+ /* First available buffer. */
+ buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
+ frame = vb2_plane_vaddr(&buf->vb, 0);
+
+ /* Copy the chunk. */
+ memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1],
+ USBTV_CHUNK * sizeof(chunk[1]));
+
+ /* Last chunk in a frame, signalling an end */
+ if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) {
+ int size = vb2_plane_size(&buf->vb, 0);
+
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ buf->vb.v4l2_buf.sequence = usbtv->sequence++;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_set_plane_payload(&buf->vb, 0, size);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ list_del(&buf->list);
+ }
+
+ spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+/* Got image data. Each packet contains a number of 256-word chunks we
+ * compose the image from. */
+static void usbtv_iso_cb(struct urb *ip)
+{
+ int ret;
+ int i;
+ struct usbtv *usbtv = (struct usbtv *)ip->context;
+
+ switch (ip->status) {
+ /* All fine. */
+ case 0:
+ break;
+ /* Device disconnected or capture stopped? */
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ return;
+ /* Unknown error. Retry. */
+ default:
+ dev_warn(usbtv->dev, "Bad response for ISO request.\n");
+ goto resubmit;
+ }
+
+ for (i = 0; i < ip->number_of_packets; i++) {
+ int size = ip->iso_frame_desc[i].actual_length;
+ unsigned char *data = ip->transfer_buffer +
+ ip->iso_frame_desc[i].offset;
+ int offset;
+
+ for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
+ usbtv_image_chunk(usbtv,
+ (u32 *)&data[USBTV_CHUNK_SIZE * offset]);
+ }
+
+resubmit:
+ ret = usb_submit_urb(ip, GFP_ATOMIC);
+ if (ret < 0)
+ dev_warn(usbtv->dev, "Could not resubmit ISO URB\n");
+}
+
+static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv)
+{
+ struct urb *ip;
+ int size = usbtv->iso_size;
+ int i;
+
+ ip = usb_alloc_urb(USBTV_ISOC_PACKETS, GFP_KERNEL);
+ if (ip == NULL)
+ return NULL;
+
+ ip->dev = usbtv->udev;
+ ip->context = usbtv;
+ ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP);
+ ip->interval = 1;
+ ip->transfer_flags = URB_ISO_ASAP;
+ ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS,
+ GFP_KERNEL);
+ ip->complete = usbtv_iso_cb;
+ ip->number_of_packets = USBTV_ISOC_PACKETS;
+ ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS;
+ for (i = 0; i < USBTV_ISOC_PACKETS; i++) {
+ ip->iso_frame_desc[i].offset = size * i;
+ ip->iso_frame_desc[i].length = size;
+ }
+
+ return ip;
+}
+
+static void usbtv_stop(struct usbtv *usbtv)
+{
+ int i;
+ unsigned long flags;
+
+ /* Cancel running transfers. */
+ for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
+ struct urb *ip = usbtv->isoc_urbs[i];
+ if (ip == NULL)
+ continue;
+ usb_kill_urb(ip);
+ kfree(ip->transfer_buffer);
+ usb_free_urb(ip);
+ usbtv->isoc_urbs[i] = NULL;
+ }
+
+ /* Return buffers to userspace. */
+ spin_lock_irqsave(&usbtv->buflock, flags);
+ while (!list_empty(&usbtv->bufs)) {
+ struct usbtv_buf *buf = list_first_entry(&usbtv->bufs,
+ struct usbtv_buf, list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ list_del(&buf->list);
+ }
+ spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+static int usbtv_start(struct usbtv *usbtv)
+{
+ int i;
+ int ret;
+
+ ret = usb_set_interface(usbtv->udev, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = usbtv_setup_capture(usbtv);
+ if (ret < 0)
+ return ret;
+
+ ret = usb_set_interface(usbtv->udev, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
+ struct urb *ip;
+
+ ip = usbtv_setup_iso_transfer(usbtv);
+ if (ip == NULL) {
+ ret = -ENOMEM;
+ goto start_fail;
+ }
+ usbtv->isoc_urbs[i] = ip;
+
+ ret = usb_submit_urb(ip, GFP_KERNEL);
+ if (ret < 0)
+ goto start_fail;
+ }
+
+ return 0;
+
+start_fail:
+ usbtv_stop(usbtv);
+ return ret;
+}
+
+struct usb_device_id usbtv_id_table[] = {
+ { USB_DEVICE(0x1b71, 0x3002) },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, usbtv_id_table);
+
+static int usbtv_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct usbtv *dev = video_drvdata(file);
+
+ strlcpy(cap->driver, "usbtv", sizeof(cap->driver));
+ strlcpy(cap->card, "usbtv", sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
+ cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int usbtv_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index > 0)
+ return -EINVAL;
+
+ strlcpy(i->name, "Composite", sizeof(i->name));
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = V4L2_STD_525_60;
+ return 0;
+}
+
+static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed",
+ sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_YUYV;
+ return 0;
+}
+
+static int usbtv_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ f->fmt.pix.width = USBTV_WIDTH;
+ f->fmt.pix.height = USBTV_HEIGHT;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.bytesperline = USBTV_WIDTH * 2;
+ f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+ return 0;
+}
+
+static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ *norm = V4L2_STD_525_60;
+ return 0;
+}
+
+static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
+{
+ if (norm & V4L2_STD_525_60)
+ return 0;
+ return -EINVAL;
+}
+
+struct v4l2_ioctl_ops usbtv_ioctl_ops = {
+ .vidioc_querycap = usbtv_querycap,
+ .vidioc_enum_input = usbtv_enum_input,
+ .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = usbtv_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = usbtv_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = usbtv_fmt_vid_cap,
+ .vidioc_g_std = usbtv_g_std,
+ .vidioc_s_std = usbtv_s_std,
+ .vidioc_g_input = usbtv_g_input,
+ .vidioc_s_input = usbtv_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+struct v4l2_file_operations usbtv_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+};
+
+static int usbtv_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *v4l_fmt, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+ if (*nbuffers < 2)
+ *nbuffers = 2;
+ *nplanes = 1;
+ sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32);
+
+ return 0;
+}
+
+static void usbtv_buf_queue(struct vb2_buffer *vb)
+{
+ struct usbtv *usbtv = vb2_get_drv_priv(vb->vb2_queue);
+ struct usbtv_buf *buf = container_of(vb, struct usbtv_buf, vb);
+ unsigned long flags;
+
+ if (usbtv->udev == NULL) {
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ spin_lock_irqsave(&usbtv->buflock, flags);
+ list_add_tail(&buf->list, &usbtv->bufs);
+ spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct usbtv *usbtv = vb2_get_drv_priv(vq);
+
+ if (usbtv->udev == NULL)
+ return -ENODEV;
+
+ return usbtv_start(usbtv);
+}
+
+static int usbtv_stop_streaming(struct vb2_queue *vq)
+{
+ struct usbtv *usbtv = vb2_get_drv_priv(vq);
+
+ if (usbtv->udev == NULL)
+ return -ENODEV;
+
+ usbtv_stop(usbtv);
+ return 0;
+}
+
+struct vb2_ops usbtv_vb2_ops = {
+ .queue_setup = usbtv_queue_setup,
+ .buf_queue = usbtv_buf_queue,
+ .start_streaming = usbtv_start_streaming,
+ .stop_streaming = usbtv_stop_streaming,
+};
+
+static void usbtv_release(struct v4l2_device *v4l2_dev)
+{
+ struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev);
+
+ v4l2_device_unregister(&usbtv->v4l2_dev);
+ vb2_queue_release(&usbtv->vb2q);
+ kfree(usbtv);
+}
+
+static int usbtv_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret;
+ int size;
+ struct device *dev = &intf->dev;
+ struct usbtv *usbtv;
+
+ /* Checks that the device is what we think it is. */
+ if (intf->num_altsetting != 2)
+ return -ENODEV;
+ if (intf->altsetting[1].desc.bNumEndpoints != 4)
+ return -ENODEV;
+
+ /* Packet size is split into 11 bits of base size and count of
+ * extra multiplies of it.*/
+ size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
+ size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
+
+ /* Device structure */
+ usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
+ if (usbtv == NULL)
+ return -ENOMEM;
+ usbtv->dev = dev;
+ usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
+ usbtv->iso_size = size;
+ spin_lock_init(&usbtv->buflock);
+ mutex_init(&usbtv->v4l2_lock);
+ mutex_init(&usbtv->vb2q_lock);
+ INIT_LIST_HEAD(&usbtv->bufs);
+
+ /* videobuf2 structure */
+ usbtv->vb2q.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ usbtv->vb2q.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ usbtv->vb2q.drv_priv = usbtv;
+ usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf);
+ usbtv->vb2q.ops = &usbtv_vb2_ops;
+ usbtv->vb2q.mem_ops = &vb2_vmalloc_memops;
+ usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ usbtv->vb2q.lock = &usbtv->vb2q_lock;
+ ret = vb2_queue_init(&usbtv->vb2q);
+ if (ret < 0) {
+ dev_warn(dev, "Could not initialize videobuf2 queue\n");
+ goto usbtv_fail;
+ }
+
+ /* v4l2 structure */
+ usbtv->v4l2_dev.release = usbtv_release;
+ ret = v4l2_device_register(dev, &usbtv->v4l2_dev);
+ if (ret < 0) {
+ dev_warn(dev, "Could not register v4l2 device\n");
+ goto v4l2_fail;
+ }
+
+ usb_set_intfdata(intf, usbtv);
+
+ /* Video structure */
+ strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
+ usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
+ usbtv->vdev.release = video_device_release_empty;
+ usbtv->vdev.fops = &usbtv_fops;
+ usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops;
+ usbtv->vdev.tvnorms = V4L2_STD_525_60;
+ usbtv->vdev.queue = &usbtv->vb2q;
+ usbtv->vdev.lock = &usbtv->v4l2_lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags);
+ video_set_drvdata(&usbtv->vdev, usbtv);
+ ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ dev_warn(dev, "Could not register video device\n");
+ goto vdev_fail;
+ }
+
+ dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+ return 0;
+
+vdev_fail:
+ v4l2_device_unregister(&usbtv->v4l2_dev);
+v4l2_fail:
+ vb2_queue_release(&usbtv->vb2q);
+usbtv_fail:
+ kfree(usbtv);
+
+ return ret;
+}
+
+static void usbtv_disconnect(struct usb_interface *intf)
+{
+ struct usbtv *usbtv = usb_get_intfdata(intf);
+
+ mutex_lock(&usbtv->vb2q_lock);
+ mutex_lock(&usbtv->v4l2_lock);
+
+ usbtv_stop(usbtv);
+ usb_set_intfdata(intf, NULL);
+ video_unregister_device(&usbtv->vdev);
+ v4l2_device_disconnect(&usbtv->v4l2_dev);
+ usb_put_dev(usbtv->udev);
+ usbtv->udev = NULL;
+
+ mutex_unlock(&usbtv->v4l2_lock);
+ mutex_unlock(&usbtv->vb2q_lock);
+
+ v4l2_device_put(&usbtv->v4l2_dev);
+}
+
+MODULE_AUTHOR("Lubomir Rintel");
+MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct usb_driver usbtv_usb_driver = {
+ .name = "usbtv",
+ .id_table = usbtv_id_table,
+ .probe = usbtv_probe,
+ .disconnect = usbtv_disconnect,
+};
+
+module_usb_driver(usbtv_usb_driver);
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index d34c2afe2c24..5c9e3123ad2e 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -467,8 +467,6 @@ static int vidioc_g_register(struct file *file, void *priv,
struct usb_usbvision *usbvision = video_drvdata(file);
int err_code;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
/* NT100x has a 8-bit register space */
err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
if (err_code < 0) {
@@ -488,8 +486,6 @@ static int vidioc_s_register(struct file *file, void *priv,
struct usb_usbvision *usbvision = video_drvdata(file);
int err_code;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
/* NT100x has a 8-bit register space */
err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
if (err_code < 0) {
@@ -608,6 +604,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ *id = usbvision->tvnorm_id;
+ return 0;
+}
+
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
@@ -1248,6 +1252,7 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1274,7 +1279,6 @@ static struct video_device usbvision_video_template = {
.name = "usbvision-video",
.release = video_device_release,
.tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
};
@@ -1307,9 +1311,6 @@ static struct video_device usbvision_radio_template = {
.name = "usbvision-radio",
.release = video_device_release,
.ioctl_ops = &usbvision_radio_ioctl_ops,
-
- .tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
};
@@ -1459,6 +1460,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
usbvision_remove_sysfs(usbvision->vdev);
usbvision_unregister_video(usbvision);
+ kfree(usbvision->alt_max_pkt_size);
usb_free_urb(usbvision->ctrl_urb);
@@ -1574,6 +1576,7 @@ static int usbvision_probe(struct usb_interface *intf,
usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
if (usbvision->alt_max_pkt_size == NULL) {
dev_err(&intf->dev, "usbvision: out of memory!\n");
+ usbvision_release(usbvision);
return -ENOMEM;
}
diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig
index 541c9f1e4c6a..6ed85efabcaa 100644
--- a/drivers/media/usb/uvc/Kconfig
+++ b/drivers/media/usb/uvc/Kconfig
@@ -1,5 +1,6 @@
config USB_VIDEO_CLASS
tristate "USB Video Class (UVC)"
+ depends on VIDEO_V4L2
select VIDEOBUF2_VMALLOC
---help---
Support for the USB Video Class (UVC). Currently only video
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 5dbefa68b1d2..81695d48c13e 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1836,8 +1836,8 @@ static int uvc_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&dev->chains);
INIT_LIST_HEAD(&dev->streams);
atomic_set(&dev->nstreams, 0);
- atomic_set(&dev->users, 0);
atomic_set(&dev->nmappings, 0);
+ mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
@@ -1950,8 +1950,13 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
/* Controls are cached on the fly so they don't need to be saved. */
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOCONTROL)
- return uvc_status_suspend(dev);
+ UVC_SC_VIDEOCONTROL) {
+ mutex_lock(&dev->lock);
+ if (dev->users)
+ uvc_status_stop(dev);
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
list_for_each_entry(stream, &dev->streams, list) {
if (stream->intf == intf)
@@ -1973,14 +1978,20 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) {
- if (reset) {
- int ret = uvc_ctrl_resume_device(dev);
+ int ret = 0;
+ if (reset) {
+ ret = uvc_ctrl_resume_device(dev);
if (ret < 0)
return ret;
}
- return uvc_status_resume(dev);
+ mutex_lock(&dev->lock);
+ if (dev->users)
+ ret = uvc_status_start(dev, GFP_NOIO);
+ mutex_unlock(&dev->lock);
+
+ return ret;
}
list_for_each_entry(stream, &dev->streams, list) {
@@ -2163,6 +2174,24 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_DEF },
+ /* Dell Alienware X51 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05a9,
+ .idProduct = 0x2643,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
+ /* Dell Studio Hybrid 140g (OmniVision webcam) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05a9,
+ .idProduct = 0x264a,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
/* Apple Built-In iSight */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index b7492775e6ae..f552ab997956 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -206,32 +206,15 @@ void uvc_status_cleanup(struct uvc_device *dev)
uvc_input_cleanup(dev);
}
-int uvc_status_start(struct uvc_device *dev)
+int uvc_status_start(struct uvc_device *dev, gfp_t flags)
{
if (dev->int_urb == NULL)
return 0;
- return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ return usb_submit_urb(dev->int_urb, flags);
}
void uvc_status_stop(struct uvc_device *dev)
{
usb_kill_urb(dev->int_urb);
}
-
-int uvc_status_suspend(struct uvc_device *dev)
-{
- if (atomic_read(&dev->users))
- usb_kill_urb(dev->int_urb);
-
- return 0;
-}
-
-int uvc_status_resume(struct uvc_device *dev)
-{
- if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
- return 0;
-
- return usb_submit_urb(dev->int_urb, GFP_NOIO);
-}
-
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index b2dc32623a71..3afff92804d3 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -498,16 +498,20 @@ static int uvc_v4l2_open(struct file *file)
return -ENOMEM;
}
- if (atomic_inc_return(&stream->dev->users) == 1) {
- ret = uvc_status_start(stream->dev);
+ mutex_lock(&stream->dev->lock);
+ if (stream->dev->users == 0) {
+ ret = uvc_status_start(stream->dev, GFP_KERNEL);
if (ret < 0) {
- atomic_dec(&stream->dev->users);
+ mutex_unlock(&stream->dev->lock);
usb_autopm_put_interface(stream->dev->intf);
kfree(handle);
return ret;
}
}
+ stream->dev->users++;
+ mutex_unlock(&stream->dev->lock);
+
v4l2_fh_init(&handle->vfh, stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
@@ -538,8 +542,10 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
- if (atomic_dec_return(&stream->dev->users) == 0)
+ mutex_lock(&stream->dev->lock);
+ if (--stream->dev->users == 0)
uvc_status_stop(stream->dev);
+ mutex_unlock(&stream->dev->lock);
usb_autopm_put_interface(stream->dev->intf);
return 0;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index af505fdd9b3f..9e35982d099a 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -514,7 +514,8 @@ struct uvc_device {
char name[32];
enum uvc_device_state state;
- atomic_t users;
+ struct mutex lock; /* Protects users */
+ unsigned int users;
atomic_t nmappings;
/* Video control interface */
@@ -660,10 +661,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
/* Status */
extern int uvc_status_init(struct uvc_device *dev);
extern void uvc_status_cleanup(struct uvc_device *dev);
-extern int uvc_status_start(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev, gfp_t flags);
extern void uvc_status_stop(struct uvc_device *dev);
-extern int uvc_status_suspend(struct uvc_device *dev);
-extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index aa50c46314b7..4c33b8d6520c 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -5,7 +5,8 @@
tuner-objs := tuner-core.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \
+ v4l2-async.o
ifeq ($(CONFIG_COMPAT),y)
videodev-objs += v4l2-compat-ioctl32.o
endif
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
new file mode 100644
index 000000000000..aae241730caa
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -0,0 +1,284 @@
+/*
+ * V4L2 asynchronous subdevice registration API
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
+{
+#if IS_ENABLED(CONFIG_I2C)
+ struct i2c_client *client = i2c_verify_client(dev);
+ return client &&
+ asd->bus_type == V4L2_ASYNC_BUS_I2C &&
+ asd->match.i2c.adapter_id == client->adapter->nr &&
+ asd->match.i2c.address == client->addr;
+#else
+ return false;
+#endif
+}
+
+static bool match_platform(struct device *dev, struct v4l2_async_subdev *asd)
+{
+ return asd->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
+ !strcmp(asd->match.platform.name, dev_name(dev));
+}
+
+static LIST_HEAD(subdev_list);
+static LIST_HEAD(notifier_list);
+static DEFINE_MUTEX(list_lock);
+
+static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev_list *asdl)
+{
+ struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+ struct v4l2_async_subdev *asd;
+ bool (*match)(struct device *,
+ struct v4l2_async_subdev *);
+
+ list_for_each_entry(asd, &notifier->waiting, list) {
+ /* bus_type has been verified valid before */
+ switch (asd->bus_type) {
+ case V4L2_ASYNC_BUS_CUSTOM:
+ match = asd->match.custom.match;
+ if (!match)
+ /* Match always */
+ return asd;
+ break;
+ case V4L2_ASYNC_BUS_PLATFORM:
+ match = match_platform;
+ break;
+ case V4L2_ASYNC_BUS_I2C:
+ match = match_i2c;
+ break;
+ default:
+ /* Cannot happen, unless someone breaks us */
+ WARN_ON(true);
+ return NULL;
+ }
+
+ /* match cannot be NULL here */
+ if (match(sd->dev, asd))
+ return asd;
+ }
+
+ return NULL;
+}
+
+static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev_list *asdl,
+ struct v4l2_async_subdev *asd)
+{
+ struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+ int ret;
+
+ /* Remove from the waiting list */
+ list_del(&asd->list);
+ asdl->asd = asd;
+ asdl->notifier = notifier;
+
+ if (notifier->bound) {
+ ret = notifier->bound(notifier, sd, asd);
+ if (ret < 0)
+ return ret;
+ }
+ /* Move from the global subdevice list to notifier's done */
+ list_move(&asdl->list, &notifier->done);
+
+ ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
+ if (ret < 0) {
+ if (notifier->unbind)
+ notifier->unbind(notifier, sd, asd);
+ return ret;
+ }
+
+ if (list_empty(&notifier->waiting) && notifier->complete)
+ return notifier->complete(notifier);
+
+ return 0;
+}
+
+static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
+{
+ struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+
+ v4l2_device_unregister_subdev(sd);
+ /* Subdevice driver will reprobe and put asdl back onto the list */
+ list_del_init(&asdl->list);
+ asdl->asd = NULL;
+ sd->dev = NULL;
+}
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+ struct v4l2_async_notifier *notifier)
+{
+ struct v4l2_async_subdev_list *asdl, *tmp;
+ struct v4l2_async_subdev *asd;
+ int i;
+
+ if (!notifier->num_subdevs || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+ return -EINVAL;
+
+ notifier->v4l2_dev = v4l2_dev;
+ INIT_LIST_HEAD(&notifier->waiting);
+ INIT_LIST_HEAD(&notifier->done);
+
+ for (i = 0; i < notifier->num_subdevs; i++) {
+ asd = notifier->subdev[i];
+
+ switch (asd->bus_type) {
+ case V4L2_ASYNC_BUS_CUSTOM:
+ case V4L2_ASYNC_BUS_PLATFORM:
+ case V4L2_ASYNC_BUS_I2C:
+ break;
+ default:
+ dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
+ "Invalid bus-type %u on %p\n",
+ asd->bus_type, asd);
+ return -EINVAL;
+ }
+ list_add_tail(&asd->list, &notifier->waiting);
+ }
+
+ mutex_lock(&list_lock);
+
+ /* Keep also completed notifiers on the list */
+ list_add(&notifier->list, &notifier_list);
+
+ list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
+ int ret;
+
+ asd = v4l2_async_belongs(notifier, asdl);
+ if (!asd)
+ continue;
+
+ ret = v4l2_async_test_notify(notifier, asdl, asd);
+ if (ret < 0) {
+ mutex_unlock(&list_lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_async_notifier_register);
+
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+{
+ struct v4l2_async_subdev_list *asdl, *tmp;
+ unsigned int notif_n_subdev = notifier->num_subdevs;
+ unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
+ struct device *dev[n_subdev];
+ int i = 0;
+
+ mutex_lock(&list_lock);
+
+ list_del(&notifier->list);
+
+ list_for_each_entry_safe(asdl, tmp, &notifier->done, list) {
+ struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+
+ dev[i] = get_device(sd->dev);
+
+ v4l2_async_cleanup(asdl);
+
+ /* If we handled USB devices, we'd have to lock the parent too */
+ device_release_driver(dev[i++]);
+
+ if (notifier->unbind)
+ notifier->unbind(notifier, sd, sd->asdl.asd);
+ }
+
+ mutex_unlock(&list_lock);
+
+ while (i--) {
+ struct device *d = dev[i];
+
+ if (d && device_attach(d) < 0) {
+ const char *name = "(none)";
+ int lock = device_trylock(d);
+
+ if (lock && d->driver)
+ name = d->driver->name;
+ dev_err(d, "Failed to re-probe to %s\n", name);
+ if (lock)
+ device_unlock(d);
+ }
+ put_device(d);
+ }
+ /*
+ * Don't care about the waiting list, it is initialised and populated
+ * upon notifier registration.
+ */
+}
+EXPORT_SYMBOL(v4l2_async_notifier_unregister);
+
+int v4l2_async_register_subdev(struct v4l2_subdev *sd)
+{
+ struct v4l2_async_subdev_list *asdl = &sd->asdl;
+ struct v4l2_async_notifier *notifier;
+
+ mutex_lock(&list_lock);
+
+ INIT_LIST_HEAD(&asdl->list);
+
+ list_for_each_entry(notifier, &notifier_list, list) {
+ struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
+ if (asd) {
+ int ret = v4l2_async_test_notify(notifier, asdl, asd);
+ mutex_unlock(&list_lock);
+ return ret;
+ }
+ }
+
+ /* None matched, wait for hot-plugging */
+ list_add(&asdl->list, &subdev_list);
+
+ mutex_unlock(&list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_async_register_subdev);
+
+void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
+{
+ struct v4l2_async_subdev_list *asdl = &sd->asdl;
+ struct v4l2_async_notifier *notifier = asdl->notifier;
+
+ if (!asdl->asd) {
+ if (!list_empty(&asdl->list))
+ v4l2_async_cleanup(asdl);
+ return;
+ }
+
+ mutex_lock(&list_lock);
+
+ list_add(&asdl->asd->list, &notifier->waiting);
+
+ v4l2_async_cleanup(asdl);
+
+ if (notifier->unbind)
+ notifier->unbind(notifier, sd, sd->asdl.asd);
+
+ mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(v4l2_async_unregister_subdev);
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
new file mode 100644
index 000000000000..b67de8642b5a
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -0,0 +1,242 @@
+/*
+ * V4L2 clock service
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/atomic.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+
+static DEFINE_MUTEX(clk_lock);
+static LIST_HEAD(clk_list);
+
+static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
+{
+ struct v4l2_clk *clk;
+
+ list_for_each_entry(clk, &clk_list, list) {
+ if (strcmp(dev_id, clk->dev_id))
+ continue;
+
+ if (!id || !clk->id || !strcmp(clk->id, id))
+ return clk;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
+{
+ struct v4l2_clk *clk;
+
+ mutex_lock(&clk_lock);
+ clk = v4l2_clk_find(dev_name(dev), id);
+
+ if (!IS_ERR(clk))
+ atomic_inc(&clk->use_count);
+ mutex_unlock(&clk_lock);
+
+ return clk;
+}
+EXPORT_SYMBOL(v4l2_clk_get);
+
+void v4l2_clk_put(struct v4l2_clk *clk)
+{
+ struct v4l2_clk *tmp;
+
+ if (IS_ERR(clk))
+ return;
+
+ mutex_lock(&clk_lock);
+
+ list_for_each_entry(tmp, &clk_list, list)
+ if (tmp == clk)
+ atomic_dec(&clk->use_count);
+
+ mutex_unlock(&clk_lock);
+}
+EXPORT_SYMBOL(v4l2_clk_put);
+
+static int v4l2_clk_lock_driver(struct v4l2_clk *clk)
+{
+ struct v4l2_clk *tmp;
+ int ret = -ENODEV;
+
+ mutex_lock(&clk_lock);
+
+ list_for_each_entry(tmp, &clk_list, list)
+ if (tmp == clk) {
+ ret = !try_module_get(clk->ops->owner);
+ if (ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ mutex_unlock(&clk_lock);
+
+ return ret;
+}
+
+static void v4l2_clk_unlock_driver(struct v4l2_clk *clk)
+{
+ module_put(clk->ops->owner);
+}
+
+int v4l2_clk_enable(struct v4l2_clk *clk)
+{
+ int ret = v4l2_clk_lock_driver(clk);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&clk->lock);
+
+ if (++clk->enable == 1 && clk->ops->enable) {
+ ret = clk->ops->enable(clk);
+ if (ret < 0)
+ clk->enable--;
+ }
+
+ mutex_unlock(&clk->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_enable);
+
+/*
+ * You might Oops if you try to disabled a disabled clock, because then the
+ * driver isn't locked and could have been unloaded by now, so, don't do that
+ */
+void v4l2_clk_disable(struct v4l2_clk *clk)
+{
+ int enable;
+
+ mutex_lock(&clk->lock);
+
+ enable = --clk->enable;
+ if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__,
+ clk->dev_id, clk->id))
+ clk->enable++;
+ else if (!enable && clk->ops->disable)
+ clk->ops->disable(clk);
+
+ mutex_unlock(&clk->lock);
+
+ v4l2_clk_unlock_driver(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_disable);
+
+unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk)
+{
+ int ret = v4l2_clk_lock_driver(clk);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&clk->lock);
+ if (!clk->ops->get_rate)
+ ret = -ENOSYS;
+ else
+ ret = clk->ops->get_rate(clk);
+ mutex_unlock(&clk->lock);
+
+ v4l2_clk_unlock_driver(clk);
+
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_get_rate);
+
+int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate)
+{
+ int ret = v4l2_clk_lock_driver(clk);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&clk->lock);
+ if (!clk->ops->set_rate)
+ ret = -ENOSYS;
+ else
+ ret = clk->ops->set_rate(clk, rate);
+ mutex_unlock(&clk->lock);
+
+ v4l2_clk_unlock_driver(clk);
+
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_set_rate);
+
+struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
+ const char *dev_id,
+ const char *id, void *priv)
+{
+ struct v4l2_clk *clk;
+ int ret;
+
+ if (!ops || !dev_id)
+ return ERR_PTR(-EINVAL);
+
+ clk = kzalloc(sizeof(struct v4l2_clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->id = kstrdup(id, GFP_KERNEL);
+ clk->dev_id = kstrdup(dev_id, GFP_KERNEL);
+ if ((id && !clk->id) || !clk->dev_id) {
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+ clk->ops = ops;
+ clk->priv = priv;
+ atomic_set(&clk->use_count, 0);
+ mutex_init(&clk->lock);
+
+ mutex_lock(&clk_lock);
+ if (!IS_ERR(v4l2_clk_find(dev_id, id))) {
+ mutex_unlock(&clk_lock);
+ ret = -EEXIST;
+ goto eexist;
+ }
+ list_add_tail(&clk->list, &clk_list);
+ mutex_unlock(&clk_lock);
+
+ return clk;
+
+eexist:
+ealloc:
+ kfree(clk->id);
+ kfree(clk->dev_id);
+ kfree(clk);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(v4l2_clk_register);
+
+void v4l2_clk_unregister(struct v4l2_clk *clk)
+{
+ if (WARN(atomic_read(&clk->use_count),
+ "%s(): Refusing to unregister ref-counted %s:%s clock!\n",
+ __func__, clk->dev_id, clk->id))
+ return;
+
+ mutex_lock(&clk_lock);
+ list_del(&clk->list);
+ mutex_unlock(&clk_lock);
+
+ kfree(clk->id);
+ kfree(clk->dev_id);
+ kfree(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_unregister);
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 3fed63f4e026..a95e5e23403f 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -61,7 +61,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
#include <linux/videodev2.h>
@@ -227,62 +226,9 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
}
EXPORT_SYMBOL(v4l2_ctrl_next);
-int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
-{
- switch (match->type) {
- case V4L2_CHIP_MATCH_BRIDGE:
- return match->addr == 0;
- default:
- return 0;
- }
-}
-EXPORT_SYMBOL(v4l2_chip_match_host);
-
-#if IS_ENABLED(CONFIG_I2C)
-int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
-{
- int len;
-
- if (c == NULL || match == NULL)
- return 0;
-
- switch (match->type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- if (c->driver == NULL || c->driver->driver.name == NULL)
- return 0;
- len = strlen(c->driver->driver.name);
- return len && !strncmp(c->driver->driver.name, match->name, len);
- case V4L2_CHIP_MATCH_I2C_ADDR:
- return c->addr == match->addr;
- case V4L2_CHIP_MATCH_SUBDEV:
- return 1;
- default:
- return 0;
- }
-}
-EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
-
-int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
- u32 ident, u32 revision)
-{
- if (!v4l2_chip_match_i2c_client(c, &chip->match))
- return 0;
- if (chip->ident == V4L2_IDENT_NONE) {
- chip->ident = ident;
- chip->revision = revision;
- }
- else {
- chip->ident = V4L2_IDENT_AMBIGUOUS;
- chip->revision = 0;
- }
- return 0;
-}
-EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
-
-/* ----------------------------------------------------------------- */
-
/* I2C Helper functions */
+#if IS_ENABLED(CONFIG_I2C)
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops)
@@ -291,6 +237,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
/* the owner is the same as the i2c_client's driver owner */
sd->owner = client->driver->driver.owner;
+ sd->dev = &client->dev;
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata(sd, client);
i2c_set_clientdata(client, sd);
@@ -301,8 +248,6 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
}
EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
-
-
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, struct i2c_board_info *info,
@@ -426,6 +371,7 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
/* the owner is the same as the spi_device's driver owner */
sd->owner = spi->dev.driver->owner;
+ sd->dev = &spi->dev;
/* spi_device and v4l2_subdev point to one another */
v4l2_set_subdevdata(sd, spi);
spi_set_drvdata(spi, sd);
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index f1295519f285..8f7a6a454a4c 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1074,7 +1074,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_TRY_DECODER_CMD:
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_G_CHIP_IDENT:
case VIDIOC_S_HW_FREQ_SEEK:
case VIDIOC_S_DV_TIMINGS:
case VIDIOC_G_DV_TIMINGS:
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 5923c5dfacd5..c8859d6ff6ad 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -495,8 +495,8 @@ static const struct file_operations v4l2_fops = {
};
/**
- * get_index - assign stream index number based on parent device
- * @vdev: video_device to assign index number to, vdev->parent should be assigned
+ * get_index - assign stream index number based on v4l2_dev
+ * @vdev: video_device to assign index number to, vdev->v4l2_dev should be assigned
*
* Note that when this is called the new device has not yet been registered
* in the video_device array, but it was able to obtain a minor number.
@@ -514,15 +514,11 @@ static int get_index(struct video_device *vdev)
static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
int i;
- /* Some drivers do not set the parent. In that case always return 0. */
- if (vdev->parent == NULL)
- return 0;
-
bitmap_zero(used, VIDEO_NUM_DEVICES);
for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
if (video_device[i] != NULL &&
- video_device[i]->parent == vdev->parent) {
+ video_device[i]->v4l2_dev == vdev->v4l2_dev) {
set_bit(video_device[i]->index, used);
}
}
@@ -596,7 +592,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
#endif
- SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
/* yes, really vidioc_subscribe_event */
SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
@@ -675,9 +670,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
if (ops->vidioc_s_std)
set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
- if (ops->vidioc_g_std || vdev->current_norm)
- set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
+ SET_VALID_IOCTL(ops, VIDIOC_G_STD, vidioc_g_std);
if (is_rx) {
SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
@@ -705,7 +699,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
if (ops->vidioc_cropcap || ops->vidioc_g_selection)
set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
- (ops->vidioc_g_std || vdev->current_norm)))
+ ops->vidioc_g_std))
set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
@@ -777,6 +771,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
/* the release callback MUST be present */
if (WARN_ON(!vdev->release))
return -EINVAL;
+ /* the v4l2_dev pointer MUST be present */
+ if (WARN_ON(!vdev->v4l2_dev))
+ return -EINVAL;
/* v4l2_fh support */
spin_lock_init(&vdev->fh_lock);
@@ -804,16 +801,14 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->vfl_type = type;
vdev->cdev = NULL;
- if (vdev->v4l2_dev) {
- if (vdev->v4l2_dev->dev)
- vdev->parent = vdev->v4l2_dev->dev;
- if (vdev->ctrl_handler == NULL)
- vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
- /* If the prio state pointer is NULL, then use the v4l2_device
- prio state. */
- if (vdev->prio == NULL)
- vdev->prio = &vdev->v4l2_dev->prio;
- }
+ if (vdev->dev_parent == NULL)
+ vdev->dev_parent = vdev->v4l2_dev->dev;
+ if (vdev->ctrl_handler == NULL)
+ vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+ /* If the prio state pointer is NULL, then use the v4l2_device
+ prio state. */
+ if (vdev->prio == NULL)
+ vdev->prio = &vdev->v4l2_dev->prio;
/* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
@@ -898,8 +893,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
/* Part 4: register the device with sysfs */
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
- if (vdev->parent)
- vdev->dev.parent = vdev->parent;
+ vdev->dev.parent = vdev->dev_parent;
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = device_register(&vdev->dev);
if (ret < 0) {
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 8ed5da2170bf..02d1b6327117 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -44,7 +44,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
- WARN_ON(!v4l2_dev->name[0]);
+ if (WARN_ON(!v4l2_dev->name[0]))
+ return -EINVAL;
return 0;
}
@@ -105,7 +106,9 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
{
struct v4l2_subdev *sd, *next;
- if (v4l2_dev == NULL)
+ /* Just return if v4l2_dev is NULL or if it was already
+ * unregistered before. */
+ if (v4l2_dev == NULL || !v4l2_dev->name[0])
return;
v4l2_device_disconnect(v4l2_dev);
@@ -135,6 +138,8 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
}
#endif
}
+ /* Mark as unregistered, thus preventing duplicate unregistrations */
+ v4l2_dev->name[0] = '\0';
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister);
@@ -269,8 +274,10 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
sd->v4l2_dev = NULL;
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (v4l2_dev->mdev)
+ if (v4l2_dev->mdev) {
+ media_entity_remove_links(&sd->entity);
media_device_unregister_entity(&sd->entity);
+ }
#endif
video_unregister_device(sd->devnode);
module_put(sd->owner);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 7658586fe5f4..68e6b5e912ff 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -26,7 +26,6 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
#include <media/videobuf2-core.h>
/* Zero out the end of the struct pointed to by p. Everything after, but
@@ -619,20 +618,6 @@ static void v4l_print_decoder_cmd(const void *arg, bool write_only)
pr_info("pts=%llu\n", p->stop.pts);
}
-static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
-{
- const struct v4l2_dbg_chip_ident *p = arg;
-
- pr_cont("type=%u, ", p->match.type);
- if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
- pr_cont("name=%.*s, ",
- (int)sizeof(p->match.name), p->match.name);
- else
- pr_cont("addr=%u, ", p->match.addr);
- pr_cont("chip_ident=%u, revision=0x%x\n",
- p->ident, p->revision);
-}
-
static void v4l_print_dbg_chip_info(const void *arg, bool write_only)
{
const struct v4l2_dbg_chip_info *p = arg;
@@ -1359,40 +1344,18 @@ static int v4l_enumstd(const struct v4l2_ioctl_ops *ops,
return 0;
}
-static int v4l_g_std(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
-{
- struct video_device *vfd = video_devdata(file);
- v4l2_std_id *id = arg;
-
- /* Calls the specific handler */
- if (ops->vidioc_g_std)
- return ops->vidioc_g_std(file, fh, arg);
- if (vfd->current_norm) {
- *id = vfd->current_norm;
- return 0;
- }
- return -ENOTTY;
-}
-
static int v4l_s_std(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct video_device *vfd = video_devdata(file);
v4l2_std_id id = *(v4l2_std_id *)arg, norm;
- int ret;
norm = id & vfd->tvnorms;
if (vfd->tvnorms && !norm) /* Check if std is supported */
return -EINVAL;
/* Calls the specific handler */
- ret = ops->vidioc_s_std(file, fh, norm);
-
- /* Updates standard information */
- if (ret >= 0)
- vfd->current_norm = norm;
- return ret;
+ return ops->vidioc_s_std(file, fh, norm);
}
static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
@@ -1402,10 +1365,10 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
v4l2_std_id *p = arg;
/*
- * If nothing detected, it should return all supported
- * standard.
- * Drivers just need to mask the std argument, in order
- * to remove the standards that don't apply from the mask.
+ * If no signal is detected, then the driver should return
+ * V4L2_STD_UNKNOWN. Otherwise it should return tvnorms with
+ * any standards that do not apply removed.
+ *
* This means that tuners, audio and video decoders can join
* their efforts to improve the standards detection.
*/
@@ -1495,7 +1458,6 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
- struct video_device *vfd = video_devdata(file);
struct v4l2_streamparm *p = arg;
v4l2_std_id std;
int ret = check_fmt(file, p->type);
@@ -1504,16 +1466,13 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
return ret;
if (ops->vidioc_g_parm)
return ops->vidioc_g_parm(file, fh, p);
- std = vfd->current_norm;
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return -EINVAL;
p->parm.capture.readbuffers = 2;
- if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std)
- ret = ops->vidioc_g_std(file, fh, &std);
+ ret = ops->vidioc_g_std(file, fh, &std);
if (ret == 0)
- v4l2_video_std_frame_period(std,
- &p->parm.capture.timeperframe);
+ v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe);
return ret;
}
@@ -1802,7 +1761,8 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops,
return v4l2_subdev_call(sd, core, g_register, p);
return -EINVAL;
}
- if (ops->vidioc_g_register)
+ if (ops->vidioc_g_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE &&
+ (ops->vidioc_g_chip_info || p->match.addr == 0))
return ops->vidioc_g_register(file, fh, p);
return -EINVAL;
#else
@@ -1829,7 +1789,8 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
return v4l2_subdev_call(sd, core, s_register, p);
return -EINVAL;
}
- if (ops->vidioc_s_register)
+ if (ops->vidioc_s_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE &&
+ (ops->vidioc_g_chip_info || p->match.addr == 0))
return ops->vidioc_s_register(file, fh, p);
return -EINVAL;
#else
@@ -1837,18 +1798,6 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
#endif
}
-static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
-{
- struct v4l2_dbg_chip_ident *p = arg;
-
- p->ident = V4L2_IDENT_NONE;
- p->revision = 0;
- if (p->match.type == V4L2_CHIP_MATCH_SUBDEV)
- return -EINVAL;
- return ops->vidioc_g_chip_ident(file, fh, p);
-}
-
static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -1864,12 +1813,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
p->flags |= V4L2_CHIP_FL_WRITABLE;
if (ops->vidioc_g_register)
p->flags |= V4L2_CHIP_FL_READABLE;
- if (vfd->v4l2_dev)
- strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
- else if (vfd->parent)
- strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name));
- else
- strlcpy(p->name, "bridge", sizeof(p->name));
+ strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
if (ops->vidioc_g_chip_info)
return ops->vidioc_g_chip_info(file, fh, arg);
if (p->match.addr)
@@ -2048,7 +1992,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)),
IOCTL_INFO_FNC(VIDIOC_S_PARM, v4l_s_parm, v4l_print_streamparm, INFO_FL_PRIO),
- IOCTL_INFO_FNC(VIDIOC_G_STD, v4l_g_std, v4l_print_std, 0),
+ IOCTL_INFO_STD(VIDIOC_G_STD, vidioc_g_std, v4l_print_std, 0),
IOCTL_INFO_FNC(VIDIOC_S_STD, v4l_s_std, v4l_print_std, INFO_FL_PRIO),
IOCTL_INFO_FNC(VIDIOC_ENUMSTD, v4l_enumstd, v4l_print_standard, INFO_FL_CLEAR(v4l2_standard, index)),
IOCTL_INFO_FNC(VIDIOC_ENUMINPUT, v4l_enuminput, v4l_print_enuminput, INFO_FL_CLEAR(v4l2_input, index)),
@@ -2098,7 +2042,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
- IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),
IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 67f572c3fba2..65411adcd0ea 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -66,11 +66,14 @@ static void __videobuf_dc_free(struct device *dev,
static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
- dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+ dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
map, map->count, vma->vm_start, vma->vm_end);
+ videobuf_queue_lock(q);
map->count++;
+ videobuf_queue_unlock(q);
}
static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -82,12 +85,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
map, map->count, vma->vm_start, vma->vm_end);
- map->count--;
- if (0 == map->count) {
+ videobuf_queue_lock(q);
+ if (!--map->count) {
struct videobuf_dma_contig_memory *mem;
dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
- videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */
if (q->streaming)
@@ -126,8 +128,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map);
- videobuf_queue_unlock(q);
}
+ videobuf_queue_unlock(q);
}
static const struct vm_operations_struct videobuf_vm_ops = {
@@ -303,14 +305,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
goto error;
/* Try to remap memory */
-
size = vma->vm_end - vma->vm_start;
- size = (size < mem->size) ? size : mem->size;
-
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = remap_pfn_range(vma, vma->vm_start,
- mem->dma_handle >> PAGE_SHIFT,
- size, vma->vm_page_prot);
+ retval = vm_iomap_memory(vma, vma->vm_start, size);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ",
retval);
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 828e7c10bd70..9db674ccdc68 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -338,11 +338,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end);
+ videobuf_queue_lock(q);
map->count++;
+ videobuf_queue_unlock(q);
}
static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -355,10 +358,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end);
- map->count--;
- if (0 == map->count) {
+ videobuf_queue_lock(q);
+ if (!--map->count) {
dprintk(1, "munmap %p q=%p\n", map, q);
- videobuf_queue_lock(q);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -374,9 +376,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->baddr = 0;
q->ops->buf_release(q, q->bufs[i]);
}
- videobuf_queue_unlock(q);
kfree(map);
}
+ videobuf_queue_unlock(q);
return;
}
diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c
index 2ff7fcc77b11..1365c651c177 100644
--- a/drivers/media/v4l2-core/videobuf-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf-vmalloc.c
@@ -54,11 +54,14 @@ MODULE_LICENSE("GPL");
static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end);
+ videobuf_queue_lock(q);
map->count++;
+ videobuf_queue_unlock(q);
}
static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -70,12 +73,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end);
- map->count--;
- if (0 == map->count) {
+ videobuf_queue_lock(q);
+ if (!--map->count) {
struct videobuf_vmalloc_memory *mem;
dprintk(1, "munmap %p q=%p\n", map, q);
- videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */
if (q->streaming)
@@ -114,8 +116,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map);
- videobuf_queue_unlock(q);
}
+ videobuf_queue_unlock(q);
return;
}
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index e3bdc3be91e1..9fc4bab2da97 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -2194,8 +2194,10 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
*/
for (i = 0; i < q->num_buffers; i++) {
fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
- if (fileio->bufs[i].vaddr == NULL)
+ if (fileio->bufs[i].vaddr == NULL) {
+ ret = -EINVAL;
goto err_reqbufs;
+ }
fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
}
diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig
index bcdbc14aeff0..8cf7563a8d92 100644
--- a/drivers/net/ethernet/mellanox/Kconfig
+++ b/drivers/net/ethernet/mellanox/Kconfig
@@ -19,5 +19,6 @@ config NET_VENDOR_MELLANOX
if NET_VENDOR_MELLANOX
source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
+source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
endif # NET_VENDOR_MELLANOX
diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile
index 37afb9683372..38fe32ef5e5f 100644
--- a/drivers/net/ethernet/mellanox/Makefile
+++ b/drivers/net/ethernet/mellanox/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_MLX4_CORE) += mlx4/
+obj-$(CONFIG_MLX5_CORE) += mlx5/core/
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
new file mode 100644
index 000000000000..21962828925a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -0,0 +1,18 @@
+#
+# Mellanox driver configuration
+#
+
+config MLX5_CORE
+ tristate
+ depends on PCI && X86
+ default n
+
+config MLX5_DEBUG
+ bool "Verbose debugging output" if (MLX5_CORE && EXPERT)
+ depends on MLX5_CORE
+ default y
+ ---help---
+ This option causes debugging code to be compiled into the
+ mlx5_core driver. The output can be turned on via the
+ debug_mask module parameter (which can also be set after
+ the driver is loaded through sysfs).
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
new file mode 100644
index 000000000000..105780bb980b
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
+
+mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
+ mad.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
new file mode 100644
index 000000000000..b215742b842f
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/bitmap.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+
+/* Handling for queue buffers -- we allocate a bunch of memory and
+ * register it in a memory region at HCA virtual address 0. If the
+ * requested size is > max_direct, we split the allocation into
+ * multiple pages, so we don't require too much contiguous memory.
+ */
+
+int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct,
+ struct mlx5_buf *buf)
+{
+ dma_addr_t t;
+
+ buf->size = size;
+ if (size <= max_direct) {
+ buf->nbufs = 1;
+ buf->npages = 1;
+ buf->page_shift = get_order(size) + PAGE_SHIFT;
+ buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev,
+ size, &t, GFP_KERNEL);
+ if (!buf->direct.buf)
+ return -ENOMEM;
+
+ buf->direct.map = t;
+
+ while (t & ((1 << buf->page_shift) - 1)) {
+ --buf->page_shift;
+ buf->npages *= 2;
+ }
+ } else {
+ int i;
+
+ buf->direct.buf = NULL;
+ buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ buf->npages = buf->nbufs;
+ buf->page_shift = PAGE_SHIFT;
+ buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
+ GFP_KERNEL);
+ if (!buf->page_list)
+ return -ENOMEM;
+
+ for (i = 0; i < buf->nbufs; i++) {
+ buf->page_list[i].buf =
+ dma_zalloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ &t, GFP_KERNEL);
+ if (!buf->page_list[i].buf)
+ goto err_free;
+
+ buf->page_list[i].map = t;
+ }
+
+ if (BITS_PER_LONG == 64) {
+ struct page **pages;
+ pages = kmalloc(sizeof(*pages) * buf->nbufs, GFP_KERNEL);
+ if (!pages)
+ goto err_free;
+ for (i = 0; i < buf->nbufs; i++)
+ pages[i] = virt_to_page(buf->page_list[i].buf);
+ buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
+ kfree(pages);
+ if (!buf->direct.buf)
+ goto err_free;
+ }
+ }
+
+ return 0;
+
+err_free:
+ mlx5_buf_free(dev, buf);
+
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(mlx5_buf_alloc);
+
+void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf)
+{
+ int i;
+
+ if (buf->nbufs == 1)
+ dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf,
+ buf->direct.map);
+ else {
+ if (BITS_PER_LONG == 64 && buf->direct.buf)
+ vunmap(buf->direct.buf);
+
+ for (i = 0; i < buf->nbufs; i++)
+ if (buf->page_list[i].buf)
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ buf->page_list[i].buf,
+ buf->page_list[i].map);
+ kfree(buf->page_list);
+ }
+}
+EXPORT_SYMBOL_GPL(mlx5_buf_free);
+
+static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device)
+{
+ struct mlx5_db_pgdir *pgdir;
+
+ pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
+ if (!pgdir)
+ return NULL;
+
+ bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE);
+ pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
+ &pgdir->db_dma, GFP_KERNEL);
+ if (!pgdir->db_page) {
+ kfree(pgdir);
+ return NULL;
+ }
+
+ return pgdir;
+}
+
+static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir,
+ struct mlx5_db *db)
+{
+ int offset;
+ int i;
+
+ i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE);
+ if (i >= MLX5_DB_PER_PAGE)
+ return -ENOMEM;
+
+ __clear_bit(i, pgdir->bitmap);
+
+ db->u.pgdir = pgdir;
+ db->index = i;
+ offset = db->index * L1_CACHE_BYTES;
+ db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page);
+ db->dma = pgdir->db_dma + offset;
+
+ return 0;
+}
+
+int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db)
+{
+ struct mlx5_db_pgdir *pgdir;
+ int ret = 0;
+
+ mutex_lock(&dev->priv.pgdir_mutex);
+
+ list_for_each_entry(pgdir, &dev->priv.pgdir_list, list)
+ if (!mlx5_alloc_db_from_pgdir(pgdir, db))
+ goto out;
+
+ pgdir = mlx5_alloc_db_pgdir(&(dev->pdev->dev));
+ if (!pgdir) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ list_add(&pgdir->list, &dev->priv.pgdir_list);
+
+ /* This should never fail -- we just allocated an empty page: */
+ WARN_ON(mlx5_alloc_db_from_pgdir(pgdir, db));
+
+out:
+ mutex_unlock(&dev->priv.pgdir_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mlx5_db_alloc);
+
+void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db)
+{
+ mutex_lock(&dev->priv.pgdir_mutex);
+
+ __set_bit(db->index, db->u.pgdir->bitmap);
+
+ if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) {
+ dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
+ db->u.pgdir->db_page, db->u.pgdir->db_dma);
+ list_del(&db->u.pgdir->list);
+ kfree(db->u.pgdir);
+ }
+
+ mutex_unlock(&dev->priv.pgdir_mutex);
+}
+EXPORT_SYMBOL_GPL(mlx5_db_free);
+
+
+void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas)
+{
+ u64 addr;
+ int i;
+
+ for (i = 0; i < buf->npages; i++) {
+ if (buf->nbufs == 1)
+ addr = buf->direct.map + (i << buf->page_shift);
+ else
+ addr = buf->page_list[i].map;
+
+ pas[i] = cpu_to_be64(addr);
+ }
+}
+EXPORT_SYMBOL_GPL(mlx5_fill_page_array);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
new file mode 100644
index 000000000000..205753a04cfc
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -0,0 +1,1515 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/io-mapping.h>
+#include <linux/mlx5/driver.h>
+#include <linux/debugfs.h>
+
+#include "mlx5_core.h"
+
+enum {
+ CMD_IF_REV = 3,
+};
+
+enum {
+ CMD_MODE_POLLING,
+ CMD_MODE_EVENTS
+};
+
+enum {
+ NUM_LONG_LISTS = 2,
+ NUM_MED_LISTS = 64,
+ LONG_LIST_SIZE = (2ULL * 1024 * 1024 * 1024 / PAGE_SIZE) * 8 + 16 +
+ MLX5_CMD_DATA_BLOCK_SIZE,
+ MED_LIST_SIZE = 16 + MLX5_CMD_DATA_BLOCK_SIZE,
+};
+
+enum {
+ MLX5_CMD_DELIVERY_STAT_OK = 0x0,
+ MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR = 0x1,
+ MLX5_CMD_DELIVERY_STAT_TOK_ERR = 0x2,
+ MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR = 0x3,
+ MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR = 0x4,
+ MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR = 0x5,
+ MLX5_CMD_DELIVERY_STAT_FW_ERR = 0x6,
+ MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR = 0x7,
+ MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR = 0x8,
+ MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR = 0x9,
+ MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10,
+};
+
+enum {
+ MLX5_CMD_STAT_OK = 0x0,
+ MLX5_CMD_STAT_INT_ERR = 0x1,
+ MLX5_CMD_STAT_BAD_OP_ERR = 0x2,
+ MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3,
+ MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4,
+ MLX5_CMD_STAT_BAD_RES_ERR = 0x5,
+ MLX5_CMD_STAT_RES_BUSY = 0x6,
+ MLX5_CMD_STAT_LIM_ERR = 0x8,
+ MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9,
+ MLX5_CMD_STAT_IX_ERR = 0xa,
+ MLX5_CMD_STAT_NO_RES_ERR = 0xf,
+ MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50,
+ MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51,
+ MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10,
+ MLX5_CMD_STAT_BAD_PKT_ERR = 0x30,
+ MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40,
+};
+
+static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
+ struct mlx5_cmd_msg *in,
+ struct mlx5_cmd_msg *out,
+ mlx5_cmd_cbk_t cbk,
+ void *context, int page_queue)
+{
+ gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
+ struct mlx5_cmd_work_ent *ent;
+
+ ent = kzalloc(sizeof(*ent), alloc_flags);
+ if (!ent)
+ return ERR_PTR(-ENOMEM);
+
+ ent->in = in;
+ ent->out = out;
+ ent->callback = cbk;
+ ent->context = context;
+ ent->cmd = cmd;
+ ent->page_queue = page_queue;
+
+ return ent;
+}
+
+static u8 alloc_token(struct mlx5_cmd *cmd)
+{
+ u8 token;
+
+ spin_lock(&cmd->token_lock);
+ token = cmd->token++ % 255 + 1;
+ spin_unlock(&cmd->token_lock);
+
+ return token;
+}
+
+static int alloc_ent(struct mlx5_cmd *cmd)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&cmd->alloc_lock, flags);
+ ret = find_first_bit(&cmd->bitmask, cmd->max_reg_cmds);
+ if (ret < cmd->max_reg_cmds)
+ clear_bit(ret, &cmd->bitmask);
+ spin_unlock_irqrestore(&cmd->alloc_lock, flags);
+
+ return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
+}
+
+static void free_ent(struct mlx5_cmd *cmd, int idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd->alloc_lock, flags);
+ set_bit(idx, &cmd->bitmask);
+ spin_unlock_irqrestore(&cmd->alloc_lock, flags);
+}
+
+static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
+{
+ return cmd->cmd_buf + (idx << cmd->log_stride);
+}
+
+static u8 xor8_buf(void *buf, int len)
+{
+ u8 *ptr = buf;
+ u8 sum = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ sum ^= ptr[i];
+
+ return sum;
+}
+
+static int verify_block_sig(struct mlx5_cmd_prot_block *block)
+{
+ if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff)
+ return -EINVAL;
+
+ if (xor8_buf(block, sizeof(*block)) != 0xff)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token)
+{
+ block->token = token;
+ block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2);
+ block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+}
+
+static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token)
+{
+ struct mlx5_cmd_mailbox *next = msg->next;
+
+ while (next) {
+ calc_block_sig(next->buf, token);
+ next = next->next;
+ }
+}
+
+static void set_signature(struct mlx5_cmd_work_ent *ent)
+{
+ ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
+ calc_chain_sig(ent->in, ent->token);
+ calc_chain_sig(ent->out, ent->token);
+}
+
+static void poll_timeout(struct mlx5_cmd_work_ent *ent)
+{
+ unsigned long poll_end = jiffies + msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC + 1000);
+ u8 own;
+
+ do {
+ own = ent->lay->status_own;
+ if (!(own & CMD_OWNER_HW)) {
+ ent->ret = 0;
+ return;
+ }
+ usleep_range(5000, 10000);
+ } while (time_before(jiffies, poll_end));
+
+ ent->ret = -ETIMEDOUT;
+}
+
+static void free_cmd(struct mlx5_cmd_work_ent *ent)
+{
+ kfree(ent);
+}
+
+
+static int verify_signature(struct mlx5_cmd_work_ent *ent)
+{
+ struct mlx5_cmd_mailbox *next = ent->out->next;
+ int err;
+ u8 sig;
+
+ sig = xor8_buf(ent->lay, sizeof(*ent->lay));
+ if (sig != 0xff)
+ return -EINVAL;
+
+ while (next) {
+ err = verify_block_sig(next->buf);
+ if (err)
+ return err;
+
+ next = next->next;
+ }
+
+ return 0;
+}
+
+static void dump_buf(void *buf, int size, int data_only, int offset)
+{
+ __be32 *p = buf;
+ int i;
+
+ for (i = 0; i < size; i += 16) {
+ pr_debug("%03x: %08x %08x %08x %08x\n", offset, be32_to_cpu(p[0]),
+ be32_to_cpu(p[1]), be32_to_cpu(p[2]),
+ be32_to_cpu(p[3]));
+ p += 4;
+ offset += 16;
+ }
+ if (!data_only)
+ pr_debug("\n");
+}
+
+const char *mlx5_command_str(int command)
+{
+ switch (command) {
+ case MLX5_CMD_OP_QUERY_HCA_CAP:
+ return "QUERY_HCA_CAP";
+
+ case MLX5_CMD_OP_SET_HCA_CAP:
+ return "SET_HCA_CAP";
+
+ case MLX5_CMD_OP_QUERY_ADAPTER:
+ return "QUERY_ADAPTER";
+
+ case MLX5_CMD_OP_INIT_HCA:
+ return "INIT_HCA";
+
+ case MLX5_CMD_OP_TEARDOWN_HCA:
+ return "TEARDOWN_HCA";
+
+ case MLX5_CMD_OP_QUERY_PAGES:
+ return "QUERY_PAGES";
+
+ case MLX5_CMD_OP_MANAGE_PAGES:
+ return "MANAGE_PAGES";
+
+ case MLX5_CMD_OP_CREATE_MKEY:
+ return "CREATE_MKEY";
+
+ case MLX5_CMD_OP_QUERY_MKEY:
+ return "QUERY_MKEY";
+
+ case MLX5_CMD_OP_DESTROY_MKEY:
+ return "DESTROY_MKEY";
+
+ case MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS:
+ return "QUERY_SPECIAL_CONTEXTS";
+
+ case MLX5_CMD_OP_CREATE_EQ:
+ return "CREATE_EQ";
+
+ case MLX5_CMD_OP_DESTROY_EQ:
+ return "DESTROY_EQ";
+
+ case MLX5_CMD_OP_QUERY_EQ:
+ return "QUERY_EQ";
+
+ case MLX5_CMD_OP_CREATE_CQ:
+ return "CREATE_CQ";
+
+ case MLX5_CMD_OP_DESTROY_CQ:
+ return "DESTROY_CQ";
+
+ case MLX5_CMD_OP_QUERY_CQ:
+ return "QUERY_CQ";
+
+ case MLX5_CMD_OP_MODIFY_CQ:
+ return "MODIFY_CQ";
+
+ case MLX5_CMD_OP_CREATE_QP:
+ return "CREATE_QP";
+
+ case MLX5_CMD_OP_DESTROY_QP:
+ return "DESTROY_QP";
+
+ case MLX5_CMD_OP_RST2INIT_QP:
+ return "RST2INIT_QP";
+
+ case MLX5_CMD_OP_INIT2RTR_QP:
+ return "INIT2RTR_QP";
+
+ case MLX5_CMD_OP_RTR2RTS_QP:
+ return "RTR2RTS_QP";
+
+ case MLX5_CMD_OP_RTS2RTS_QP:
+ return "RTS2RTS_QP";
+
+ case MLX5_CMD_OP_SQERR2RTS_QP:
+ return "SQERR2RTS_QP";
+
+ case MLX5_CMD_OP_2ERR_QP:
+ return "2ERR_QP";
+
+ case MLX5_CMD_OP_RTS2SQD_QP:
+ return "RTS2SQD_QP";
+
+ case MLX5_CMD_OP_SQD2RTS_QP:
+ return "SQD2RTS_QP";
+
+ case MLX5_CMD_OP_2RST_QP:
+ return "2RST_QP";
+
+ case MLX5_CMD_OP_QUERY_QP:
+ return "QUERY_QP";
+
+ case MLX5_CMD_OP_CONF_SQP:
+ return "CONF_SQP";
+
+ case MLX5_CMD_OP_MAD_IFC:
+ return "MAD_IFC";
+
+ case MLX5_CMD_OP_INIT2INIT_QP:
+ return "INIT2INIT_QP";
+
+ case MLX5_CMD_OP_SUSPEND_QP:
+ return "SUSPEND_QP";
+
+ case MLX5_CMD_OP_UNSUSPEND_QP:
+ return "UNSUSPEND_QP";
+
+ case MLX5_CMD_OP_SQD2SQD_QP:
+ return "SQD2SQD_QP";
+
+ case MLX5_CMD_OP_ALLOC_QP_COUNTER_SET:
+ return "ALLOC_QP_COUNTER_SET";
+
+ case MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET:
+ return "DEALLOC_QP_COUNTER_SET";
+
+ case MLX5_CMD_OP_QUERY_QP_COUNTER_SET:
+ return "QUERY_QP_COUNTER_SET";
+
+ case MLX5_CMD_OP_CREATE_PSV:
+ return "CREATE_PSV";
+
+ case MLX5_CMD_OP_DESTROY_PSV:
+ return "DESTROY_PSV";
+
+ case MLX5_CMD_OP_QUERY_PSV:
+ return "QUERY_PSV";
+
+ case MLX5_CMD_OP_QUERY_SIG_RULE_TABLE:
+ return "QUERY_SIG_RULE_TABLE";
+
+ case MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE:
+ return "QUERY_BLOCK_SIZE_TABLE";
+
+ case MLX5_CMD_OP_CREATE_SRQ:
+ return "CREATE_SRQ";
+
+ case MLX5_CMD_OP_DESTROY_SRQ:
+ return "DESTROY_SRQ";
+
+ case MLX5_CMD_OP_QUERY_SRQ:
+ return "QUERY_SRQ";
+
+ case MLX5_CMD_OP_ARM_RQ:
+ return "ARM_RQ";
+
+ case MLX5_CMD_OP_RESIZE_SRQ:
+ return "RESIZE_SRQ";
+
+ case MLX5_CMD_OP_ALLOC_PD:
+ return "ALLOC_PD";
+
+ case MLX5_CMD_OP_DEALLOC_PD:
+ return "DEALLOC_PD";
+
+ case MLX5_CMD_OP_ALLOC_UAR:
+ return "ALLOC_UAR";
+
+ case MLX5_CMD_OP_DEALLOC_UAR:
+ return "DEALLOC_UAR";
+
+ case MLX5_CMD_OP_ATTACH_TO_MCG:
+ return "ATTACH_TO_MCG";
+
+ case MLX5_CMD_OP_DETACH_FROM_MCG:
+ return "DETACH_FROM_MCG";
+
+ case MLX5_CMD_OP_ALLOC_XRCD:
+ return "ALLOC_XRCD";
+
+ case MLX5_CMD_OP_DEALLOC_XRCD:
+ return "DEALLOC_XRCD";
+
+ case MLX5_CMD_OP_ACCESS_REG:
+ return "MLX5_CMD_OP_ACCESS_REG";
+
+ default: return "unknown command opcode";
+ }
+}
+
+static void dump_command(struct mlx5_core_dev *dev,
+ struct mlx5_cmd_work_ent *ent, int input)
+{
+ u16 op = be16_to_cpu(((struct mlx5_inbox_hdr *)(ent->lay->in))->opcode);
+ struct mlx5_cmd_msg *msg = input ? ent->in : ent->out;
+ struct mlx5_cmd_mailbox *next = msg->next;
+ int data_only;
+ int offset = 0;
+ int dump_len;
+
+ data_only = !!(mlx5_core_debug_mask & (1 << MLX5_CMD_DATA));
+
+ if (data_only)
+ mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_DATA,
+ "dump command data %s(0x%x) %s\n",
+ mlx5_command_str(op), op,
+ input ? "INPUT" : "OUTPUT");
+ else
+ mlx5_core_dbg(dev, "dump command %s(0x%x) %s\n",
+ mlx5_command_str(op), op,
+ input ? "INPUT" : "OUTPUT");
+
+ if (data_only) {
+ if (input) {
+ dump_buf(ent->lay->in, sizeof(ent->lay->in), 1, offset);
+ offset += sizeof(ent->lay->in);
+ } else {
+ dump_buf(ent->lay->out, sizeof(ent->lay->out), 1, offset);
+ offset += sizeof(ent->lay->out);
+ }
+ } else {
+ dump_buf(ent->lay, sizeof(*ent->lay), 0, offset);
+ offset += sizeof(*ent->lay);
+ }
+
+ while (next && offset < msg->len) {
+ if (data_only) {
+ dump_len = min_t(int, MLX5_CMD_DATA_BLOCK_SIZE, msg->len - offset);
+ dump_buf(next->buf, dump_len, 1, offset);
+ offset += MLX5_CMD_DATA_BLOCK_SIZE;
+ } else {
+ mlx5_core_dbg(dev, "command block:\n");
+ dump_buf(next->buf, sizeof(struct mlx5_cmd_prot_block), 0, offset);
+ offset += sizeof(struct mlx5_cmd_prot_block);
+ }
+ next = next->next;
+ }
+
+ if (data_only)
+ pr_debug("\n");
+}
+
+static void cmd_work_handler(struct work_struct *work)
+{
+ struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
+ struct mlx5_cmd *cmd = ent->cmd;
+ struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd);
+ struct mlx5_cmd_layout *lay;
+ struct semaphore *sem;
+
+ sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
+ down(sem);
+ if (!ent->page_queue) {
+ ent->idx = alloc_ent(cmd);
+ if (ent->idx < 0) {
+ mlx5_core_err(dev, "failed to allocate command entry\n");
+ up(sem);
+ return;
+ }
+ } else {
+ ent->idx = cmd->max_reg_cmds;
+ }
+
+ ent->token = alloc_token(cmd);
+ cmd->ent_arr[ent->idx] = ent;
+ lay = get_inst(cmd, ent->idx);
+ ent->lay = lay;
+ memset(lay, 0, sizeof(*lay));
+ memcpy(lay->in, ent->in->first.data, sizeof(lay->in));
+ if (ent->in->next)
+ lay->in_ptr = cpu_to_be64(ent->in->next->dma);
+ lay->inlen = cpu_to_be32(ent->in->len);
+ if (ent->out->next)
+ lay->out_ptr = cpu_to_be64(ent->out->next->dma);
+ lay->outlen = cpu_to_be32(ent->out->len);
+ lay->type = MLX5_PCI_CMD_XPORT;
+ lay->token = ent->token;
+ lay->status_own = CMD_OWNER_HW;
+ if (!cmd->checksum_disabled)
+ set_signature(ent);
+ dump_command(dev, ent, 1);
+ ktime_get_ts(&ent->ts1);
+
+ /* ring doorbell after the descriptor is valid */
+ wmb();
+ iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
+ mlx5_core_dbg(dev, "write 0x%x to command doorbell\n", 1 << ent->idx);
+ mmiowb();
+ if (cmd->mode == CMD_MODE_POLLING) {
+ poll_timeout(ent);
+ /* make sure we read the descriptor after ownership is SW */
+ rmb();
+ mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
+ }
+}
+
+static const char *deliv_status_to_str(u8 status)
+{
+ switch (status) {
+ case MLX5_CMD_DELIVERY_STAT_OK:
+ return "no errors";
+ case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR:
+ return "signature error";
+ case MLX5_CMD_DELIVERY_STAT_TOK_ERR:
+ return "token error";
+ case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR:
+ return "bad block number";
+ case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR:
+ return "output pointer not aligned to block size";
+ case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR:
+ return "input pointer not aligned to block size";
+ case MLX5_CMD_DELIVERY_STAT_FW_ERR:
+ return "firmware internal error";
+ case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR:
+ return "command input length error";
+ case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR:
+ return "command ouput length error";
+ case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR:
+ return "reserved fields not cleared";
+ case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR:
+ return "bad command descriptor type";
+ default:
+ return "unknown status code";
+ }
+}
+
+static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
+{
+ struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data);
+
+ return be16_to_cpu(hdr->opcode);
+}
+
+static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
+{
+ unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
+ struct mlx5_cmd *cmd = &dev->cmd;
+ int err;
+
+ if (cmd->mode == CMD_MODE_POLLING) {
+ wait_for_completion(&ent->done);
+ err = ent->ret;
+ } else {
+ if (!wait_for_completion_timeout(&ent->done, timeout))
+ err = -ETIMEDOUT;
+ else
+ err = 0;
+ }
+ if (err == -ETIMEDOUT) {
+ mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
+ mlx5_command_str(msg_to_opcode(ent->in)),
+ msg_to_opcode(ent->in));
+ }
+ mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", err,
+ deliv_status_to_str(ent->status), ent->status);
+
+ return err;
+}
+
+/* Notes:
+ * 1. Callback functions may not sleep
+ * 2. page queue commands do not support asynchrous completion
+ */
+static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
+ struct mlx5_cmd_msg *out, mlx5_cmd_cbk_t callback,
+ void *context, int page_queue, u8 *status)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ struct mlx5_cmd_work_ent *ent;
+ ktime_t t1, t2, delta;
+ struct mlx5_cmd_stats *stats;
+ int err = 0;
+ s64 ds;
+ u16 op;
+
+ if (callback && page_queue)
+ return -EINVAL;
+
+ ent = alloc_cmd(cmd, in, out, callback, context, page_queue);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
+ if (!callback)
+ init_completion(&ent->done);
+
+ INIT_WORK(&ent->work, cmd_work_handler);
+ if (page_queue) {
+ cmd_work_handler(&ent->work);
+ } else if (!queue_work(cmd->wq, &ent->work)) {
+ mlx5_core_warn(dev, "failed to queue work\n");
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ if (!callback) {
+ err = wait_func(dev, ent);
+ if (err == -ETIMEDOUT)
+ goto out;
+
+ t1 = timespec_to_ktime(ent->ts1);
+ t2 = timespec_to_ktime(ent->ts2);
+ delta = ktime_sub(t2, t1);
+ ds = ktime_to_ns(delta);
+ op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
+ if (op < ARRAY_SIZE(cmd->stats)) {
+ stats = &cmd->stats[op];
+ spin_lock(&stats->lock);
+ stats->sum += ds;
+ ++stats->n;
+ spin_unlock(&stats->lock);
+ }
+ mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
+ "fw exec time for %s is %lld nsec\n",
+ mlx5_command_str(op), ds);
+ *status = ent->status;
+ free_cmd(ent);
+ }
+
+ return err;
+
+out_free:
+ free_cmd(ent);
+out:
+ return err;
+}
+
+static ssize_t dbg_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_core_dev *dev = filp->private_data;
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ char lbuf[3];
+ int err;
+
+ if (!dbg->in_msg || !dbg->out_msg)
+ return -ENOMEM;
+
+ if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+ return -EFAULT;
+
+ lbuf[sizeof(lbuf) - 1] = 0;
+
+ if (strcmp(lbuf, "go"))
+ return -EINVAL;
+
+ err = mlx5_cmd_exec(dev, dbg->in_msg, dbg->inlen, dbg->out_msg, dbg->outlen);
+
+ return err ? err : count;
+}
+
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = dbg_write,
+};
+
+static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size)
+{
+ struct mlx5_cmd_prot_block *block;
+ struct mlx5_cmd_mailbox *next;
+ int copy;
+
+ if (!to || !from)
+ return -ENOMEM;
+
+ copy = min_t(int, size, sizeof(to->first.data));
+ memcpy(to->first.data, from, copy);
+ size -= copy;
+ from += copy;
+
+ next = to->next;
+ while (size) {
+ if (!next) {
+ /* this is a BUG */
+ return -ENOMEM;
+ }
+
+ copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
+ block = next->buf;
+ memcpy(block->data, from, copy);
+ from += copy;
+ size -= copy;
+ next = next->next;
+ }
+
+ return 0;
+}
+
+static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size)
+{
+ struct mlx5_cmd_prot_block *block;
+ struct mlx5_cmd_mailbox *next;
+ int copy;
+
+ if (!to || !from)
+ return -ENOMEM;
+
+ copy = min_t(int, size, sizeof(from->first.data));
+ memcpy(to, from->first.data, copy);
+ size -= copy;
+ to += copy;
+
+ next = from->next;
+ while (size) {
+ if (!next) {
+ /* this is a BUG */
+ return -ENOMEM;
+ }
+
+ copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
+ block = next->buf;
+ if (xor8_buf(block, sizeof(*block)) != 0xff)
+ return -EINVAL;
+
+ memcpy(to, block->data, copy);
+ to += copy;
+ size -= copy;
+ next = next->next;
+ }
+
+ return 0;
+}
+
+static struct mlx5_cmd_mailbox *alloc_cmd_box(struct mlx5_core_dev *dev,
+ gfp_t flags)
+{
+ struct mlx5_cmd_mailbox *mailbox;
+
+ mailbox = kmalloc(sizeof(*mailbox), flags);
+ if (!mailbox)
+ return ERR_PTR(-ENOMEM);
+
+ mailbox->buf = pci_pool_alloc(dev->cmd.pool, flags,
+ &mailbox->dma);
+ if (!mailbox->buf) {
+ mlx5_core_dbg(dev, "failed allocation\n");
+ kfree(mailbox);
+ return ERR_PTR(-ENOMEM);
+ }
+ memset(mailbox->buf, 0, sizeof(struct mlx5_cmd_prot_block));
+ mailbox->next = NULL;
+
+ return mailbox;
+}
+
+static void free_cmd_box(struct mlx5_core_dev *dev,
+ struct mlx5_cmd_mailbox *mailbox)
+{
+ pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+ kfree(mailbox);
+}
+
+static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,
+ gfp_t flags, int size)
+{
+ struct mlx5_cmd_mailbox *tmp, *head = NULL;
+ struct mlx5_cmd_prot_block *block;
+ struct mlx5_cmd_msg *msg;
+ int blen;
+ int err;
+ int n;
+ int i;
+
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return ERR_PTR(-ENOMEM);
+
+ blen = size - min_t(int, sizeof(msg->first.data), size);
+ n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1) / MLX5_CMD_DATA_BLOCK_SIZE;
+
+ for (i = 0; i < n; i++) {
+ tmp = alloc_cmd_box(dev, flags);
+ if (IS_ERR(tmp)) {
+ mlx5_core_warn(dev, "failed allocating block\n");
+ err = PTR_ERR(tmp);
+ goto err_alloc;
+ }
+
+ block = tmp->buf;
+ tmp->next = head;
+ block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0);
+ block->block_num = cpu_to_be32(n - i - 1);
+ head = tmp;
+ }
+ msg->next = head;
+ msg->len = size;
+ return msg;
+
+err_alloc:
+ while (head) {
+ tmp = head->next;
+ free_cmd_box(dev, head);
+ head = tmp;
+ }
+ kfree(msg);
+
+ return ERR_PTR(err);
+}
+
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+ struct mlx5_cmd_msg *msg)
+{
+ struct mlx5_cmd_mailbox *head = msg->next;
+ struct mlx5_cmd_mailbox *next;
+
+ while (head) {
+ next = head->next;
+ free_cmd_box(dev, head);
+ head = next;
+ }
+ kfree(msg);
+}
+
+static ssize_t data_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_core_dev *dev = filp->private_data;
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ void *ptr;
+ int err;
+
+ if (*pos != 0)
+ return -EINVAL;
+
+ kfree(dbg->in_msg);
+ dbg->in_msg = NULL;
+ dbg->inlen = 0;
+
+ ptr = kzalloc(count, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ if (copy_from_user(ptr, buf, count)) {
+ err = -EFAULT;
+ goto out;
+ }
+ dbg->in_msg = ptr;
+ dbg->inlen = count;
+
+ *pos = count;
+
+ return count;
+
+out:
+ kfree(ptr);
+ return err;
+}
+
+static ssize_t data_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_core_dev *dev = filp->private_data;
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ int copy;
+
+ if (*pos)
+ return 0;
+
+ if (!dbg->out_msg)
+ return -ENOMEM;
+
+ copy = min_t(int, count, dbg->outlen);
+ if (copy_to_user(buf, dbg->out_msg, copy))
+ return -EFAULT;
+
+ *pos += copy;
+
+ return copy;
+}
+
+static const struct file_operations dfops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = data_write,
+ .read = data_read,
+};
+
+static ssize_t outlen_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_core_dev *dev = filp->private_data;
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ char outlen[8];
+ int err;
+
+ if (*pos)
+ return 0;
+
+ err = snprintf(outlen, sizeof(outlen), "%d", dbg->outlen);
+ if (err < 0)
+ return err;
+
+ if (copy_to_user(buf, &outlen, err))
+ return -EFAULT;
+
+ *pos += err;
+
+ return err;
+}
+
+static ssize_t outlen_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_core_dev *dev = filp->private_data;
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ char outlen_str[8];
+ int outlen;
+ void *ptr;
+ int err;
+
+ if (*pos != 0 || count > 6)
+ return -EINVAL;
+
+ kfree(dbg->out_msg);
+ dbg->out_msg = NULL;
+ dbg->outlen = 0;
+
+ if (copy_from_user(outlen_str, buf, count))
+ return -EFAULT;
+
+ outlen_str[7] = 0;
+
+ err = sscanf(outlen_str, "%d", &outlen);
+ if (err < 0)
+ return err;
+
+ ptr = kzalloc(outlen, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dbg->out_msg = ptr;
+ dbg->outlen = outlen;
+
+ *pos = count;
+
+ return count;
+}
+
+static const struct file_operations olfops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = outlen_write,
+ .read = outlen_read,
+};
+
+static void set_wqname(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+
+ snprintf(cmd->wq_name, sizeof(cmd->wq_name), "mlx5_cmd_%s",
+ dev_name(&dev->pdev->dev));
+}
+
+static void clean_debug_files(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+
+ if (!mlx5_debugfs_root)
+ return;
+
+ mlx5_cmdif_debugfs_cleanup(dev);
+ debugfs_remove_recursive(dbg->dbg_root);
+}
+
+static int create_debugfs_files(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+ int err = -ENOMEM;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ dbg->dbg_root = debugfs_create_dir("cmd", dev->priv.dbg_root);
+ if (!dbg->dbg_root)
+ return err;
+
+ dbg->dbg_in = debugfs_create_file("in", 0400, dbg->dbg_root,
+ dev, &dfops);
+ if (!dbg->dbg_in)
+ goto err_dbg;
+
+ dbg->dbg_out = debugfs_create_file("out", 0200, dbg->dbg_root,
+ dev, &dfops);
+ if (!dbg->dbg_out)
+ goto err_dbg;
+
+ dbg->dbg_outlen = debugfs_create_file("out_len", 0600, dbg->dbg_root,
+ dev, &olfops);
+ if (!dbg->dbg_outlen)
+ goto err_dbg;
+
+ dbg->dbg_status = debugfs_create_u8("status", 0600, dbg->dbg_root,
+ &dbg->status);
+ if (!dbg->dbg_status)
+ goto err_dbg;
+
+ dbg->dbg_run = debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops);
+ if (!dbg->dbg_run)
+ goto err_dbg;
+
+ mlx5_cmdif_debugfs_init(dev);
+
+ return 0;
+
+err_dbg:
+ clean_debug_files(dev);
+ return err;
+}
+
+void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ int i;
+
+ for (i = 0; i < cmd->max_reg_cmds; i++)
+ down(&cmd->sem);
+
+ down(&cmd->pages_sem);
+
+ flush_workqueue(cmd->wq);
+
+ cmd->mode = CMD_MODE_EVENTS;
+
+ up(&cmd->pages_sem);
+ for (i = 0; i < cmd->max_reg_cmds; i++)
+ up(&cmd->sem);
+}
+
+void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ int i;
+
+ for (i = 0; i < cmd->max_reg_cmds; i++)
+ down(&cmd->sem);
+
+ down(&cmd->pages_sem);
+
+ flush_workqueue(cmd->wq);
+ cmd->mode = CMD_MODE_POLLING;
+
+ up(&cmd->pages_sem);
+ for (i = 0; i < cmd->max_reg_cmds; i++)
+ up(&cmd->sem);
+}
+
+void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ struct mlx5_cmd_work_ent *ent;
+ mlx5_cmd_cbk_t callback;
+ void *context;
+ int err;
+ int i;
+
+ for (i = 0; i < (1 << cmd->log_sz); i++) {
+ if (test_bit(i, &vector)) {
+ ent = cmd->ent_arr[i];
+ ktime_get_ts(&ent->ts2);
+ memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
+ dump_command(dev, ent, 0);
+ if (!ent->ret) {
+ if (!cmd->checksum_disabled)
+ ent->ret = verify_signature(ent);
+ else
+ ent->ret = 0;
+ ent->status = ent->lay->status_own >> 1;
+ mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n",
+ ent->ret, deliv_status_to_str(ent->status), ent->status);
+ }
+ free_ent(cmd, ent->idx);
+ if (ent->callback) {
+ callback = ent->callback;
+ context = ent->context;
+ err = ent->ret;
+ free_cmd(ent);
+ callback(err, context);
+ } else {
+ complete(&ent->done);
+ }
+ if (ent->page_queue)
+ up(&cmd->pages_sem);
+ else
+ up(&cmd->sem);
+ }
+ }
+}
+EXPORT_SYMBOL(mlx5_cmd_comp_handler);
+
+static int status_to_err(u8 status)
+{
+ return status ? -1 : 0; /* TBD more meaningful codes */
+}
+
+static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size)
+{
+ struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM);
+ struct mlx5_cmd *cmd = &dev->cmd;
+ struct cache_ent *ent = NULL;
+
+ if (in_size > MED_LIST_SIZE && in_size <= LONG_LIST_SIZE)
+ ent = &cmd->cache.large;
+ else if (in_size > 16 && in_size <= MED_LIST_SIZE)
+ ent = &cmd->cache.med;
+
+ if (ent) {
+ spin_lock(&ent->lock);
+ if (!list_empty(&ent->head)) {
+ msg = list_entry(ent->head.next, typeof(*msg), list);
+ /* For cached lists, we must explicitly state what is
+ * the real size
+ */
+ msg->len = in_size;
+ list_del(&msg->list);
+ }
+ spin_unlock(&ent->lock);
+ }
+
+ if (IS_ERR(msg))
+ msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, in_size);
+
+ return msg;
+}
+
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
+{
+ if (msg->cache) {
+ spin_lock(&msg->cache->lock);
+ list_add_tail(&msg->list, &msg->cache->head);
+ spin_unlock(&msg->cache->lock);
+ } else {
+ mlx5_free_cmd_msg(dev, msg);
+ }
+}
+
+static int is_manage_pages(struct mlx5_inbox_hdr *in)
+{
+ return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES;
+}
+
+int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
+ int out_size)
+{
+ struct mlx5_cmd_msg *inb;
+ struct mlx5_cmd_msg *outb;
+ int pages_queue;
+ int err;
+ u8 status = 0;
+
+ pages_queue = is_manage_pages(in);
+
+ inb = alloc_msg(dev, in_size);
+ if (IS_ERR(inb)) {
+ err = PTR_ERR(inb);
+ return err;
+ }
+
+ err = mlx5_copy_to_msg(inb, in, in_size);
+ if (err) {
+ mlx5_core_warn(dev, "err %d\n", err);
+ goto out_in;
+ }
+
+ outb = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, out_size);
+ if (IS_ERR(outb)) {
+ err = PTR_ERR(outb);
+ goto out_in;
+ }
+
+ err = mlx5_cmd_invoke(dev, inb, outb, NULL, NULL, pages_queue, &status);
+ if (err)
+ goto out_out;
+
+ mlx5_core_dbg(dev, "err %d, status %d\n", err, status);
+ if (status) {
+ err = status_to_err(status);
+ goto out_out;
+ }
+
+ err = mlx5_copy_from_msg(out, outb, out_size);
+
+out_out:
+ mlx5_free_cmd_msg(dev, outb);
+
+out_in:
+ free_msg(dev, inb);
+ return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_exec);
+
+static void destroy_msg_cache(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ struct mlx5_cmd_msg *msg;
+ struct mlx5_cmd_msg *n;
+
+ list_for_each_entry_safe(msg, n, &cmd->cache.large.head, list) {
+ list_del(&msg->list);
+ mlx5_free_cmd_msg(dev, msg);
+ }
+
+ list_for_each_entry_safe(msg, n, &cmd->cache.med.head, list) {
+ list_del(&msg->list);
+ mlx5_free_cmd_msg(dev, msg);
+ }
+}
+
+static int create_msg_cache(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ struct mlx5_cmd_msg *msg;
+ int err;
+ int i;
+
+ spin_lock_init(&cmd->cache.large.lock);
+ INIT_LIST_HEAD(&cmd->cache.large.head);
+ spin_lock_init(&cmd->cache.med.lock);
+ INIT_LIST_HEAD(&cmd->cache.med.head);
+
+ for (i = 0; i < NUM_LONG_LISTS; i++) {
+ msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE);
+ if (IS_ERR(msg)) {
+ err = PTR_ERR(msg);
+ goto ex_err;
+ }
+ msg->cache = &cmd->cache.large;
+ list_add_tail(&msg->list, &cmd->cache.large.head);
+ }
+
+ for (i = 0; i < NUM_MED_LISTS; i++) {
+ msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE);
+ if (IS_ERR(msg)) {
+ err = PTR_ERR(msg);
+ goto ex_err;
+ }
+ msg->cache = &cmd->cache.med;
+ list_add_tail(&msg->list, &cmd->cache.med.head);
+ }
+
+ return 0;
+
+ex_err:
+ destroy_msg_cache(dev);
+ return err;
+}
+
+int mlx5_cmd_init(struct mlx5_core_dev *dev)
+{
+ int size = sizeof(struct mlx5_cmd_prot_block);
+ int align = roundup_pow_of_two(size);
+ struct mlx5_cmd *cmd = &dev->cmd;
+ u32 cmd_h, cmd_l;
+ u16 cmd_if_rev;
+ int err;
+ int i;
+
+ cmd_if_rev = cmdif_rev(dev);
+ if (cmd_if_rev != CMD_IF_REV) {
+ dev_err(&dev->pdev->dev,
+ "Driver cmdif rev(%d) differs from firmware's(%d)\n",
+ CMD_IF_REV, cmd_if_rev);
+ return -EINVAL;
+ }
+
+ cmd->pool = pci_pool_create("mlx5_cmd", dev->pdev, size, align, 0);
+ if (!cmd->pool)
+ return -ENOMEM;
+
+ cmd->cmd_buf = (void *)__get_free_pages(GFP_ATOMIC, 0);
+ if (!cmd->cmd_buf) {
+ err = -ENOMEM;
+ goto err_free_pool;
+ }
+ cmd->dma = dma_map_single(&dev->pdev->dev, cmd->cmd_buf, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(&dev->pdev->dev, cmd->dma)) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff;
+ cmd->log_sz = cmd_l >> 4 & 0xf;
+ cmd->log_stride = cmd_l & 0xf;
+ if (1 << cmd->log_sz > MLX5_MAX_COMMANDS) {
+ dev_err(&dev->pdev->dev, "firmware reports too many outstanding commands %d\n",
+ 1 << cmd->log_sz);
+ err = -EINVAL;
+ goto err_map;
+ }
+
+ if (cmd->log_sz + cmd->log_stride > PAGE_SHIFT) {
+ dev_err(&dev->pdev->dev, "command queue size overflow\n");
+ err = -EINVAL;
+ goto err_map;
+ }
+
+ cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
+ cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
+
+ cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
+ if (cmd->cmdif_rev > CMD_IF_REV) {
+ dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n",
+ CMD_IF_REV, cmd->cmdif_rev);
+ err = -ENOTSUPP;
+ goto err_map;
+ }
+
+ spin_lock_init(&cmd->alloc_lock);
+ spin_lock_init(&cmd->token_lock);
+ for (i = 0; i < ARRAY_SIZE(cmd->stats); i++)
+ spin_lock_init(&cmd->stats[i].lock);
+
+ sema_init(&cmd->sem, cmd->max_reg_cmds);
+ sema_init(&cmd->pages_sem, 1);
+
+ cmd_h = (u32)((u64)(cmd->dma) >> 32);
+ cmd_l = (u32)(cmd->dma);
+ if (cmd_l & 0xfff) {
+ dev_err(&dev->pdev->dev, "invalid command queue address\n");
+ err = -ENOMEM;
+ goto err_map;
+ }
+
+ iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h);
+ iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz);
+
+ /* Make sure firmware sees the complete address before we proceed */
+ wmb();
+
+ mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
+
+ cmd->mode = CMD_MODE_POLLING;
+
+ err = create_msg_cache(dev);
+ if (err) {
+ dev_err(&dev->pdev->dev, "failed to create command cache\n");
+ goto err_map;
+ }
+
+ set_wqname(dev);
+ cmd->wq = create_singlethread_workqueue(cmd->wq_name);
+ if (!cmd->wq) {
+ dev_err(&dev->pdev->dev, "failed to create command workqueue\n");
+ err = -ENOMEM;
+ goto err_cache;
+ }
+
+ err = create_debugfs_files(dev);
+ if (err) {
+ err = -ENOMEM;
+ goto err_wq;
+ }
+
+ return 0;
+
+err_wq:
+ destroy_workqueue(cmd->wq);
+
+err_cache:
+ destroy_msg_cache(dev);
+
+err_map:
+ dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+err_free:
+ free_pages((unsigned long)cmd->cmd_buf, 0);
+
+err_free_pool:
+ pci_pool_destroy(cmd->pool);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_init);
+
+void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+
+ clean_debug_files(dev);
+ destroy_workqueue(cmd->wq);
+ destroy_msg_cache(dev);
+ dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)cmd->cmd_buf, 0);
+ pci_pool_destroy(cmd->pool);
+}
+EXPORT_SYMBOL(mlx5_cmd_cleanup);
+
+static const char *cmd_status_str(u8 status)
+{
+ switch (status) {
+ case MLX5_CMD_STAT_OK:
+ return "OK";
+ case MLX5_CMD_STAT_INT_ERR:
+ return "internal error";
+ case MLX5_CMD_STAT_BAD_OP_ERR:
+ return "bad operation";
+ case MLX5_CMD_STAT_BAD_PARAM_ERR:
+ return "bad parameter";
+ case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:
+ return "bad system state";
+ case MLX5_CMD_STAT_BAD_RES_ERR:
+ return "bad resource";
+ case MLX5_CMD_STAT_RES_BUSY:
+ return "resource busy";
+ case MLX5_CMD_STAT_LIM_ERR:
+ return "limits exceeded";
+ case MLX5_CMD_STAT_BAD_RES_STATE_ERR:
+ return "bad resource state";
+ case MLX5_CMD_STAT_IX_ERR:
+ return "bad index";
+ case MLX5_CMD_STAT_NO_RES_ERR:
+ return "no resources";
+ case MLX5_CMD_STAT_BAD_INP_LEN_ERR:
+ return "bad input length";
+ case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:
+ return "bad output length";
+ case MLX5_CMD_STAT_BAD_QP_STATE_ERR:
+ return "bad QP state";
+ case MLX5_CMD_STAT_BAD_PKT_ERR:
+ return "bad packet (discarded)";
+ case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:
+ return "bad size too many outstanding CQEs";
+ default:
+ return "unknown status";
+ }
+}
+
+int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)
+{
+ if (!hdr->status)
+ return 0;
+
+ pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n",
+ cmd_status_str(hdr->status), hdr->status,
+ be32_to_cpu(hdr->syndrome));
+
+ switch (hdr->status) {
+ case MLX5_CMD_STAT_OK: return 0;
+ case MLX5_CMD_STAT_INT_ERR: return -EIO;
+ case MLX5_CMD_STAT_BAD_OP_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_BAD_PARAM_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_BAD_SYS_STATE_ERR: return -EIO;
+ case MLX5_CMD_STAT_BAD_RES_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_RES_BUSY: return -EBUSY;
+ case MLX5_CMD_STAT_LIM_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_BAD_RES_STATE_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_IX_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_NO_RES_ERR: return -EAGAIN;
+ case MLX5_CMD_STAT_BAD_INP_LEN_ERR: return -EIO;
+ case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR: return -EIO;
+ case MLX5_CMD_STAT_BAD_QP_STATE_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_BAD_PKT_ERR: return -EINVAL;
+ case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR: return -EINVAL;
+ default: return -EIO;
+ }
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
new file mode 100644
index 000000000000..c2d660be6f76
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_verbs.h>
+#include <linux/mlx5/cq.h>
+#include "mlx5_core.h"
+
+void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn)
+{
+ struct mlx5_core_cq *cq;
+ struct mlx5_cq_table *table = &dev->priv.cq_table;
+
+ spin_lock(&table->lock);
+ cq = radix_tree_lookup(&table->tree, cqn);
+ if (likely(cq))
+ atomic_inc(&cq->refcount);
+ spin_unlock(&table->lock);
+
+ if (!cq) {
+ mlx5_core_warn(dev, "Completion event for bogus CQ 0x%x\n", cqn);
+ return;
+ }
+
+ ++cq->arm_sn;
+
+ cq->comp(cq);
+
+ if (atomic_dec_and_test(&cq->refcount))
+ complete(&cq->free);
+}
+
+void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type)
+{
+ struct mlx5_cq_table *table = &dev->priv.cq_table;
+ struct mlx5_core_cq *cq;
+
+ spin_lock(&table->lock);
+
+ cq = radix_tree_lookup(&table->tree, cqn);
+ if (cq)
+ atomic_inc(&cq->refcount);
+
+ spin_unlock(&table->lock);
+
+ if (!cq) {
+ mlx5_core_warn(dev, "Async event for bogus CQ 0x%x\n", cqn);
+ return;
+ }
+
+ cq->event(cq, event_type);
+
+ if (atomic_dec_and_test(&cq->refcount))
+ complete(&cq->free);
+}
+
+
+int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+ struct mlx5_create_cq_mbox_in *in, int inlen)
+{
+ int err;
+ struct mlx5_cq_table *table = &dev->priv.cq_table;
+ struct mlx5_create_cq_mbox_out out;
+ struct mlx5_destroy_cq_mbox_in din;
+ struct mlx5_destroy_cq_mbox_out dout;
+
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_CQ);
+ memset(&out, 0, sizeof(out));
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ cq->cqn = be32_to_cpu(out.cqn) & 0xffffff;
+ cq->cons_index = 0;
+ cq->arm_sn = 0;
+ atomic_set(&cq->refcount, 1);
+ init_completion(&cq->free);
+
+ spin_lock_irq(&table->lock);
+ err = radix_tree_insert(&table->tree, cq->cqn, cq);
+ spin_unlock_irq(&table->lock);
+ if (err)
+ goto err_cmd;
+
+ cq->pid = current->pid;
+ err = mlx5_debug_cq_add(dev, cq);
+ if (err)
+ mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
+ cq->cqn);
+
+ return 0;
+
+err_cmd:
+ memset(&din, 0, sizeof(din));
+ memset(&dout, 0, sizeof(dout));
+ din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ);
+ mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout));
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_cq);
+
+int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+ struct mlx5_cq_table *table = &dev->priv.cq_table;
+ struct mlx5_destroy_cq_mbox_in in;
+ struct mlx5_destroy_cq_mbox_out out;
+ struct mlx5_core_cq *tmp;
+ int err;
+
+ spin_lock_irq(&table->lock);
+ tmp = radix_tree_delete(&table->tree, cq->cqn);
+ spin_unlock_irq(&table->lock);
+ if (!tmp) {
+ mlx5_core_warn(dev, "cq 0x%x not found in tree\n", cq->cqn);
+ return -EINVAL;
+ }
+ if (tmp != cq) {
+ mlx5_core_warn(dev, "corruption on srqn 0x%x\n", cq->cqn);
+ return -EINVAL;
+ }
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ);
+ in.cqn = cpu_to_be32(cq->cqn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ synchronize_irq(cq->irqn);
+
+ mlx5_debug_cq_remove(dev, cq);
+ if (atomic_dec_and_test(&cq->refcount))
+ complete(&cq->free);
+ wait_for_completion(&cq->free);
+
+ return 0;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_cq);
+
+int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+ struct mlx5_query_cq_mbox_out *out)
+{
+ struct mlx5_query_cq_mbox_in in;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(out, 0, sizeof(*out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_CQ);
+ in.cqn = cpu_to_be32(cq->cqn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+ if (err)
+ return err;
+
+ if (out->hdr.status)
+ return mlx5_cmd_status_to_err(&out->hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_cq);
+
+
+int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+ int type, struct mlx5_cq_modify_params *params)
+{
+ return -ENOSYS;
+}
+
+int mlx5_init_cq_table(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cq_table *table = &dev->priv.cq_table;
+ int err;
+
+ spin_lock_init(&table->lock);
+ INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+ err = mlx5_cq_debugfs_init(dev);
+
+ return err;
+}
+
+void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev)
+{
+ mlx5_cq_debugfs_cleanup(dev);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
new file mode 100644
index 000000000000..4273c06e2e96
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+
+enum {
+ QP_PID,
+ QP_STATE,
+ QP_XPORT,
+ QP_MTU,
+ QP_N_RECV,
+ QP_RECV_SZ,
+ QP_N_SEND,
+ QP_LOG_PG_SZ,
+ QP_RQPN,
+};
+
+static char *qp_fields[] = {
+ [QP_PID] = "pid",
+ [QP_STATE] = "state",
+ [QP_XPORT] = "transport",
+ [QP_MTU] = "mtu",
+ [QP_N_RECV] = "num_recv",
+ [QP_RECV_SZ] = "rcv_wqe_sz",
+ [QP_N_SEND] = "num_send",
+ [QP_LOG_PG_SZ] = "log2_page_sz",
+ [QP_RQPN] = "remote_qpn",
+};
+
+enum {
+ EQ_NUM_EQES,
+ EQ_INTR,
+ EQ_LOG_PG_SZ,
+};
+
+static char *eq_fields[] = {
+ [EQ_NUM_EQES] = "num_eqes",
+ [EQ_INTR] = "intr",
+ [EQ_LOG_PG_SZ] = "log_page_size",
+};
+
+enum {
+ CQ_PID,
+ CQ_NUM_CQES,
+ CQ_LOG_PG_SZ,
+};
+
+static char *cq_fields[] = {
+ [CQ_PID] = "pid",
+ [CQ_NUM_CQES] = "num_cqes",
+ [CQ_LOG_PG_SZ] = "log_page_size",
+};
+
+struct dentry *mlx5_debugfs_root;
+EXPORT_SYMBOL(mlx5_debugfs_root);
+
+void mlx5_register_debugfs(void)
+{
+ mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL);
+ if (IS_ERR_OR_NULL(mlx5_debugfs_root))
+ mlx5_debugfs_root = NULL;
+}
+
+void mlx5_unregister_debugfs(void)
+{
+ debugfs_remove(mlx5_debugfs_root);
+}
+
+int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ atomic_set(&dev->num_qps, 0);
+
+ dev->priv.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg_root);
+ if (!dev->priv.qp_debugfs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(dev->priv.qp_debugfs);
+}
+
+int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ dev->priv.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg_root);
+ if (!dev->priv.eq_debugfs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(dev->priv.eq_debugfs);
+}
+
+static ssize_t average_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_cmd_stats *stats;
+ u64 field = 0;
+ int ret;
+ char tbuf[22];
+
+ if (*pos)
+ return 0;
+
+ stats = filp->private_data;
+ spin_lock(&stats->lock);
+ if (stats->n)
+ field = stats->sum / stats->n;
+ spin_unlock(&stats->lock);
+ ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
+ if (ret > 0) {
+ if (copy_to_user(buf, tbuf, ret))
+ return -EFAULT;
+ }
+
+ *pos += ret;
+ return ret;
+}
+
+
+static ssize_t average_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct mlx5_cmd_stats *stats;
+
+ stats = filp->private_data;
+ spin_lock(&stats->lock);
+ stats->sum = 0;
+ stats->n = 0;
+ spin_unlock(&stats->lock);
+
+ *pos += count;
+
+ return count;
+}
+
+static const struct file_operations stats_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = average_read,
+ .write = average_write,
+};
+
+int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_stats *stats;
+ struct dentry **cmd;
+ const char *namep;
+ int err;
+ int i;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ cmd = &dev->priv.cmdif_debugfs;
+ *cmd = debugfs_create_dir("commands", dev->priv.dbg_root);
+ if (!*cmd)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) {
+ stats = &dev->cmd.stats[i];
+ namep = mlx5_command_str(i);
+ if (strcmp(namep, "unknown command opcode")) {
+ stats->root = debugfs_create_dir(namep, *cmd);
+ if (!stats->root) {
+ mlx5_core_warn(dev, "failed adding command %d\n",
+ i);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ stats->avg = debugfs_create_file("average", 0400,
+ stats->root, stats,
+ &stats_fops);
+ if (!stats->avg) {
+ mlx5_core_warn(dev, "failed creating debugfs file\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ stats->count = debugfs_create_u64("n", 0400,
+ stats->root,
+ &stats->n);
+ if (!stats->count) {
+ mlx5_core_warn(dev, "failed creating debugfs file\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ }
+
+ return 0;
+out:
+ debugfs_remove_recursive(dev->priv.cmdif_debugfs);
+ return err;
+}
+
+void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(dev->priv.cmdif_debugfs);
+}
+
+int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ dev->priv.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg_root);
+ if (!dev->priv.cq_debugfs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(dev->priv.cq_debugfs);
+}
+
+static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
+ int index)
+{
+ struct mlx5_query_qp_mbox_out *out;
+ struct mlx5_qp_context *ctx;
+ u64 param = 0;
+ int err;
+ int no_sq;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return param;
+
+ err = mlx5_core_qp_query(dev, qp, out, sizeof(*out));
+ if (err) {
+ mlx5_core_warn(dev, "failed to query qp\n");
+ goto out;
+ }
+
+ ctx = &out->ctx;
+ switch (index) {
+ case QP_PID:
+ param = qp->pid;
+ break;
+ case QP_STATE:
+ param = be32_to_cpu(ctx->flags) >> 28;
+ break;
+ case QP_XPORT:
+ param = (be32_to_cpu(ctx->flags) >> 16) & 0xff;
+ break;
+ case QP_MTU:
+ param = ctx->mtu_msgmax >> 5;
+ break;
+ case QP_N_RECV:
+ param = 1 << ((ctx->rq_size_stride >> 3) & 0xf);
+ break;
+ case QP_RECV_SZ:
+ param = 1 << ((ctx->rq_size_stride & 7) + 4);
+ break;
+ case QP_N_SEND:
+ no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15;
+ if (!no_sq)
+ param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11);
+ else
+ param = 0;
+ break;
+ case QP_LOG_PG_SZ:
+ param = (be32_to_cpu(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f;
+ param += 12;
+ break;
+ case QP_RQPN:
+ param = be32_to_cpu(ctx->log_pg_sz_remote_qpn) & 0xffffff;
+ break;
+ }
+
+out:
+ kfree(out);
+ return param;
+}
+
+static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+ int index)
+{
+ struct mlx5_query_eq_mbox_out *out;
+ struct mlx5_eq_context *ctx;
+ u64 param = 0;
+ int err;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return param;
+
+ ctx = &out->ctx;
+
+ err = mlx5_core_eq_query(dev, eq, out, sizeof(*out));
+ if (err) {
+ mlx5_core_warn(dev, "failed to query eq\n");
+ goto out;
+ }
+
+ switch (index) {
+ case EQ_NUM_EQES:
+ param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
+ break;
+ case EQ_INTR:
+ param = ctx->intr;
+ break;
+ case EQ_LOG_PG_SZ:
+ param = (ctx->log_page_size & 0x1f) + 12;
+ break;
+ }
+
+out:
+ kfree(out);
+ return param;
+}
+
+static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+ int index)
+{
+ struct mlx5_query_cq_mbox_out *out;
+ struct mlx5_cq_context *ctx;
+ u64 param = 0;
+ int err;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return param;
+
+ ctx = &out->ctx;
+
+ err = mlx5_core_query_cq(dev, cq, out);
+ if (err) {
+ mlx5_core_warn(dev, "failed to query cq\n");
+ goto out;
+ }
+
+ switch (index) {
+ case CQ_PID:
+ param = cq->pid;
+ break;
+ case CQ_NUM_CQES:
+ param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
+ break;
+ case CQ_LOG_PG_SZ:
+ param = (ctx->log_pg_sz & 0x1f) + 12;
+ break;
+ }
+
+out:
+ kfree(out);
+ return param;
+}
+
+static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct mlx5_field_desc *desc;
+ struct mlx5_rsc_debug *d;
+ char tbuf[18];
+ u64 field;
+ int ret;
+
+ if (*pos)
+ return 0;
+
+ desc = filp->private_data;
+ d = (void *)(desc - desc->i) - sizeof(*d);
+ switch (d->type) {
+ case MLX5_DBG_RSC_QP:
+ field = qp_read_field(d->dev, d->object, desc->i);
+ break;
+
+ case MLX5_DBG_RSC_EQ:
+ field = eq_read_field(d->dev, d->object, desc->i);
+ break;
+
+ case MLX5_DBG_RSC_CQ:
+ field = cq_read_field(d->dev, d->object, desc->i);
+ break;
+
+ default:
+ mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
+ return -EINVAL;
+ }
+
+ ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
+ if (ret > 0) {
+ if (copy_to_user(buf, tbuf, ret))
+ return -EFAULT;
+ }
+
+ *pos += ret;
+ return ret;
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = dbg_read,
+};
+
+static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
+ struct dentry *root, struct mlx5_rsc_debug **dbg,
+ int rsn, char **field, int nfile, void *data)
+{
+ struct mlx5_rsc_debug *d;
+ char resn[32];
+ int err;
+ int i;
+
+ d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ d->dev = dev;
+ d->object = data;
+ d->type = type;
+ sprintf(resn, "0x%x", rsn);
+ d->root = debugfs_create_dir(resn, root);
+ if (!d->root) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ for (i = 0; i < nfile; i++) {
+ d->fields[i].i = i;
+ d->fields[i].dent = debugfs_create_file(field[i], 0400,
+ d->root, &d->fields[i],
+ &fops);
+ if (!d->fields[i].dent) {
+ err = -ENOMEM;
+ goto out_rem;
+ }
+ }
+ *dbg = d;
+
+ return 0;
+out_rem:
+ debugfs_remove_recursive(d->root);
+
+out_free:
+ kfree(d);
+ return err;
+}
+
+static void rem_res_tree(struct mlx5_rsc_debug *d)
+{
+ debugfs_remove_recursive(d->root);
+ kfree(d);
+}
+
+int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
+{
+ int err;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs,
+ &qp->dbg, qp->qpn, qp_fields,
+ ARRAY_SIZE(qp_fields), qp);
+ if (err)
+ qp->dbg = NULL;
+
+ return err;
+}
+
+void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ if (qp->dbg)
+ rem_res_tree(qp->dbg);
+}
+
+
+int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+ int err;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs,
+ &eq->dbg, eq->eqn, eq_fields,
+ ARRAY_SIZE(eq_fields), eq);
+ if (err)
+ eq->dbg = NULL;
+
+ return err;
+}
+
+void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ if (eq->dbg)
+ rem_res_tree(eq->dbg);
+}
+
+int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+ int err;
+
+ if (!mlx5_debugfs_root)
+ return 0;
+
+ err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs,
+ &cq->dbg, cq->cqn, cq_fields,
+ ARRAY_SIZE(cq_fields), cq);
+ if (err)
+ cq->dbg = NULL;
+
+ return err;
+}
+
+void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+ if (!mlx5_debugfs_root)
+ return;
+
+ if (cq->dbg)
+ rem_res_tree(cq->dbg);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
new file mode 100644
index 000000000000..c02cbcfd0fb8
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+ MLX5_EQE_SIZE = sizeof(struct mlx5_eqe),
+ MLX5_EQE_OWNER_INIT_VAL = 0x1,
+};
+
+enum {
+ MLX5_EQ_STATE_ARMED = 0x9,
+ MLX5_EQ_STATE_FIRED = 0xa,
+ MLX5_EQ_STATE_ALWAYS_ARMED = 0xb,
+};
+
+enum {
+ MLX5_NUM_SPARE_EQE = 0x80,
+ MLX5_NUM_ASYNC_EQE = 0x100,
+ MLX5_NUM_CMD_EQE = 32,
+};
+
+enum {
+ MLX5_EQ_DOORBEL_OFFSET = 0x40,
+};
+
+#define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \
+ (1ull << MLX5_EVENT_TYPE_COMM_EST) | \
+ (1ull << MLX5_EVENT_TYPE_SQ_DRAINED) | \
+ (1ull << MLX5_EVENT_TYPE_CQ_ERROR) | \
+ (1ull << MLX5_EVENT_TYPE_WQ_CATAS_ERROR) | \
+ (1ull << MLX5_EVENT_TYPE_PATH_MIG_FAILED) | \
+ (1ull << MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
+ (1ull << MLX5_EVENT_TYPE_WQ_ACCESS_ERROR) | \
+ (1ull << MLX5_EVENT_TYPE_PORT_CHANGE) | \
+ (1ull << MLX5_EVENT_TYPE_SRQ_CATAS_ERROR) | \
+ (1ull << MLX5_EVENT_TYPE_SRQ_LAST_WQE) | \
+ (1ull << MLX5_EVENT_TYPE_SRQ_RQ_LIMIT))
+
+struct map_eq_in {
+ u64 mask;
+ u32 reserved;
+ u32 unmap_eqn;
+};
+
+struct cre_des_eq {
+ u8 reserved[15];
+ u8 eqn;
+};
+
+static int mlx5_cmd_destroy_eq(struct mlx5_core_dev *dev, u8 eqn)
+{
+ struct mlx5_destroy_eq_mbox_in in;
+ struct mlx5_destroy_eq_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_EQ);
+ in.eqn = eqn;
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (!err)
+ goto ex;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ex:
+ return err;
+}
+
+static struct mlx5_eqe *get_eqe(struct mlx5_eq *eq, u32 entry)
+{
+ return mlx5_buf_offset(&eq->buf, entry * MLX5_EQE_SIZE);
+}
+
+static struct mlx5_eqe *next_eqe_sw(struct mlx5_eq *eq)
+{
+ struct mlx5_eqe *eqe = get_eqe(eq, eq->cons_index & (eq->nent - 1));
+
+ return ((eqe->owner & 1) ^ !!(eq->cons_index & eq->nent)) ? NULL : eqe;
+}
+
+static const char *eqe_type_str(u8 type)
+{
+ switch (type) {
+ case MLX5_EVENT_TYPE_COMP:
+ return "MLX5_EVENT_TYPE_COMP";
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ return "MLX5_EVENT_TYPE_PATH_MIG";
+ case MLX5_EVENT_TYPE_COMM_EST:
+ return "MLX5_EVENT_TYPE_COMM_EST";
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ return "MLX5_EVENT_TYPE_SQ_DRAINED";
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ return "MLX5_EVENT_TYPE_SRQ_LAST_WQE";
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ return "MLX5_EVENT_TYPE_SRQ_RQ_LIMIT";
+ case MLX5_EVENT_TYPE_CQ_ERROR:
+ return "MLX5_EVENT_TYPE_CQ_ERROR";
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ return "MLX5_EVENT_TYPE_WQ_CATAS_ERROR";
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ return "MLX5_EVENT_TYPE_PATH_MIG_FAILED";
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ return "MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR";
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ return "MLX5_EVENT_TYPE_WQ_ACCESS_ERROR";
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ return "MLX5_EVENT_TYPE_SRQ_CATAS_ERROR";
+ case MLX5_EVENT_TYPE_INTERNAL_ERROR:
+ return "MLX5_EVENT_TYPE_INTERNAL_ERROR";
+ case MLX5_EVENT_TYPE_PORT_CHANGE:
+ return "MLX5_EVENT_TYPE_PORT_CHANGE";
+ case MLX5_EVENT_TYPE_GPIO_EVENT:
+ return "MLX5_EVENT_TYPE_GPIO_EVENT";
+ case MLX5_EVENT_TYPE_REMOTE_CONFIG:
+ return "MLX5_EVENT_TYPE_REMOTE_CONFIG";
+ case MLX5_EVENT_TYPE_DB_BF_CONGESTION:
+ return "MLX5_EVENT_TYPE_DB_BF_CONGESTION";
+ case MLX5_EVENT_TYPE_STALL_EVENT:
+ return "MLX5_EVENT_TYPE_STALL_EVENT";
+ case MLX5_EVENT_TYPE_CMD:
+ return "MLX5_EVENT_TYPE_CMD";
+ case MLX5_EVENT_TYPE_PAGE_REQUEST:
+ return "MLX5_EVENT_TYPE_PAGE_REQUEST";
+ default:
+ return "Unrecognized event";
+ }
+}
+
+static enum mlx5_dev_event port_subtype_event(u8 subtype)
+{
+ switch (subtype) {
+ case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+ return MLX5_DEV_EVENT_PORT_DOWN;
+ case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+ return MLX5_DEV_EVENT_PORT_UP;
+ case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+ return MLX5_DEV_EVENT_PORT_INITIALIZED;
+ case MLX5_PORT_CHANGE_SUBTYPE_LID:
+ return MLX5_DEV_EVENT_LID_CHANGE;
+ case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+ return MLX5_DEV_EVENT_PKEY_CHANGE;
+ case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+ return MLX5_DEV_EVENT_GUID_CHANGE;
+ case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+ return MLX5_DEV_EVENT_CLIENT_REREG;
+ }
+ return -1;
+}
+
+static void eq_update_ci(struct mlx5_eq *eq, int arm)
+{
+ __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2);
+ u32 val = (eq->cons_index & 0xffffff) | (eq->eqn << 24);
+ __raw_writel((__force u32) cpu_to_be32(val), addr);
+ /* We still want ordering, just not swabbing, so add a barrier */
+ mb();
+}
+
+static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+ struct mlx5_eqe *eqe;
+ int eqes_found = 0;
+ int set_ci = 0;
+ u32 cqn;
+ u32 srqn;
+ u8 port;
+
+ while ((eqe = next_eqe_sw(eq))) {
+ /*
+ * Make sure we read EQ entry contents after we've
+ * checked the ownership bit.
+ */
+ rmb();
+
+ mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type));
+ switch (eqe->type) {
+ case MLX5_EVENT_TYPE_COMP:
+ cqn = be32_to_cpu(eqe->data.comp.cqn) & 0xffffff;
+ mlx5_cq_completion(dev, cqn);
+ break;
+
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ case MLX5_EVENT_TYPE_COMM_EST:
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ mlx5_core_dbg(dev, "event %s(%d) arrived\n",
+ eqe_type_str(eqe->type), eqe->type);
+ mlx5_qp_event(dev, be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff,
+ eqe->type);
+ break;
+
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ srqn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
+ mlx5_core_dbg(dev, "SRQ event %s(%d): srqn 0x%x\n",
+ eqe_type_str(eqe->type), eqe->type, srqn);
+ mlx5_srq_event(dev, srqn, eqe->type);
+ break;
+
+ case MLX5_EVENT_TYPE_CMD:
+ mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector));
+ break;
+
+ case MLX5_EVENT_TYPE_PORT_CHANGE:
+ port = (eqe->data.port.port >> 4) & 0xf;
+ switch (eqe->sub_type) {
+ case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+ case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+ case MLX5_PORT_CHANGE_SUBTYPE_LID:
+ case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+ case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+ case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+ case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+ dev->event(dev, port_subtype_event(eqe->sub_type), &port);
+ break;
+ default:
+ mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
+ port, eqe->sub_type);
+ }
+ break;
+ case MLX5_EVENT_TYPE_CQ_ERROR:
+ cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
+ mlx5_core_warn(dev, "CQ error on CQN 0x%x, syndrom 0x%x\n",
+ cqn, eqe->data.cq_err.syndrome);
+ mlx5_cq_event(dev, cqn, eqe->type);
+ break;
+
+ case MLX5_EVENT_TYPE_PAGE_REQUEST:
+ {
+ u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id);
+ s16 npages = be16_to_cpu(eqe->data.req_pages.num_pages);
+
+ mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages);
+ mlx5_core_req_pages_handler(dev, func_id, npages);
+ }
+ break;
+
+
+ default:
+ mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn);
+ break;
+ }
+
+ ++eq->cons_index;
+ eqes_found = 1;
+ ++set_ci;
+
+ /* The HCA will think the queue has overflowed if we
+ * don't tell it we've been processing events. We
+ * create our EQs with MLX5_NUM_SPARE_EQE extra
+ * entries, so we must update our consumer index at
+ * least that often.
+ */
+ if (unlikely(set_ci >= MLX5_NUM_SPARE_EQE)) {
+ eq_update_ci(eq, 0);
+ set_ci = 0;
+ }
+ }
+
+ eq_update_ci(eq, 1);
+
+ return eqes_found;
+}
+
+static irqreturn_t mlx5_msix_handler(int irq, void *eq_ptr)
+{
+ struct mlx5_eq *eq = eq_ptr;
+ struct mlx5_core_dev *dev = eq->dev;
+
+ mlx5_eq_int(dev, eq);
+
+ /* MSI-X vectors always belong to us */
+ return IRQ_HANDLED;
+}
+
+static void init_eq_buf(struct mlx5_eq *eq)
+{
+ struct mlx5_eqe *eqe;
+ int i;
+
+ for (i = 0; i < eq->nent; i++) {
+ eqe = get_eqe(eq, i);
+ eqe->owner = MLX5_EQE_OWNER_INIT_VAL;
+ }
+}
+
+int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
+ int nent, u64 mask, const char *name, struct mlx5_uar *uar)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+ struct mlx5_create_eq_mbox_in *in;
+ struct mlx5_create_eq_mbox_out out;
+ int err;
+ int inlen;
+
+ eq->nent = roundup_pow_of_two(nent + MLX5_NUM_SPARE_EQE);
+ err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, 2 * PAGE_SIZE,
+ &eq->buf);
+ if (err)
+ return err;
+
+ init_eq_buf(eq);
+
+ inlen = sizeof(*in) + sizeof(in->pas[0]) * eq->buf.npages;
+ in = mlx5_vzalloc(inlen);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_buf;
+ }
+ memset(&out, 0, sizeof(out));
+
+ mlx5_fill_page_array(&eq->buf, in->pas);
+
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_EQ);
+ in->ctx.log_sz_usr_page = cpu_to_be32(ilog2(eq->nent) << 24 | uar->index);
+ in->ctx.intr = vecidx;
+ in->ctx.log_page_size = PAGE_SHIFT - 12;
+ in->events_mask = cpu_to_be64(mask);
+
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ if (err)
+ goto err_in;
+
+ if (out.hdr.status) {
+ err = mlx5_cmd_status_to_err(&out.hdr);
+ goto err_in;
+ }
+
+ eq->eqn = out.eq_number;
+ err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
+ name, eq);
+ if (err)
+ goto err_eq;
+
+ eq->irqn = vecidx;
+ eq->dev = dev;
+ eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET;
+
+ err = mlx5_debug_eq_add(dev, eq);
+ if (err)
+ goto err_irq;
+
+ /* EQs are created in ARMED state
+ */
+ eq_update_ci(eq, 1);
+
+ mlx5_vfree(in);
+ return 0;
+
+err_irq:
+ free_irq(table->msix_arr[vecidx].vector, eq);
+
+err_eq:
+ mlx5_cmd_destroy_eq(dev, eq->eqn);
+
+err_in:
+ mlx5_vfree(in);
+
+err_buf:
+ mlx5_buf_free(dev, &eq->buf);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_create_map_eq);
+
+int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+ int err;
+
+ mlx5_debug_eq_remove(dev, eq);
+ free_irq(table->msix_arr[eq->irqn].vector, eq);
+ err = mlx5_cmd_destroy_eq(dev, eq->eqn);
+ if (err)
+ mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
+ eq->eqn);
+ mlx5_buf_free(dev, &eq->buf);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_destroy_unmap_eq);
+
+int mlx5_eq_init(struct mlx5_core_dev *dev)
+{
+ int err;
+
+ spin_lock_init(&dev->priv.eq_table.lock);
+
+ err = mlx5_eq_debugfs_init(dev);
+
+ return err;
+}
+
+
+void mlx5_eq_cleanup(struct mlx5_core_dev *dev)
+{
+ mlx5_eq_debugfs_cleanup(dev);
+}
+
+int mlx5_start_eqs(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+ int err;
+
+ err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
+ MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
+ "mlx5_cmd_eq", &dev->priv.uuari.uars[0]);
+ if (err) {
+ mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
+ return err;
+ }
+
+ mlx5_cmd_use_events(dev);
+
+ err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC,
+ MLX5_NUM_ASYNC_EQE, MLX5_ASYNC_EVENT_MASK,
+ "mlx5_async_eq", &dev->priv.uuari.uars[0]);
+ if (err) {
+ mlx5_core_warn(dev, "failed to create async EQ %d\n", err);
+ goto err1;
+ }
+
+ err = mlx5_create_map_eq(dev, &table->pages_eq,
+ MLX5_EQ_VEC_PAGES,
+ dev->caps.max_vf + 1,
+ 1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq",
+ &dev->priv.uuari.uars[0]);
+ if (err) {
+ mlx5_core_warn(dev, "failed to create pages EQ %d\n", err);
+ goto err2;
+ }
+
+ return err;
+
+err2:
+ mlx5_destroy_unmap_eq(dev, &table->async_eq);
+
+err1:
+ mlx5_cmd_use_polling(dev);
+ mlx5_destroy_unmap_eq(dev, &table->cmd_eq);
+ return err;
+}
+
+int mlx5_stop_eqs(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+ int err;
+
+ err = mlx5_destroy_unmap_eq(dev, &table->pages_eq);
+ if (err)
+ return err;
+
+ mlx5_destroy_unmap_eq(dev, &table->async_eq);
+ mlx5_cmd_use_polling(dev);
+
+ err = mlx5_destroy_unmap_eq(dev, &table->cmd_eq);
+ if (err)
+ mlx5_cmd_use_events(dev);
+
+ return err;
+}
+
+int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+ struct mlx5_query_eq_mbox_out *out, int outlen)
+{
+ struct mlx5_query_eq_mbox_in in;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(out, 0, outlen);
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_EQ);
+ in.eqn = eq->eqn;
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+ if (err)
+ return err;
+
+ if (out->hdr.status)
+ err = mlx5_cmd_status_to_err(&out->hdr);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_eq_query);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
new file mode 100644
index 000000000000..72a5222447f5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/module.h>
+#include "mlx5_core.h"
+
+int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_query_adapter_mbox_out *out;
+ struct mlx5_cmd_query_adapter_mbox_in in;
+ int err;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ memset(&in, 0, sizeof(in));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_ADAPTER);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+ if (err)
+ goto out_out;
+
+ if (out->hdr.status) {
+ err = mlx5_cmd_status_to_err(&out->hdr);
+ goto out_out;
+ }
+
+ memcpy(dev->board_id, out->vsd_psid, sizeof(out->vsd_psid));
+
+out_out:
+ kfree(out);
+
+ return err;
+}
+
+int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
+ struct mlx5_caps *caps)
+{
+ struct mlx5_cmd_query_hca_cap_mbox_out *out;
+ struct mlx5_cmd_query_hca_cap_mbox_in in;
+ struct mlx5_query_special_ctxs_mbox_out ctx_out;
+ struct mlx5_query_special_ctxs_mbox_in ctx_in;
+ int err;
+ u16 t16;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ memset(&in, 0, sizeof(in));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP);
+ in.hdr.opmod = cpu_to_be16(0x1);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+ if (err)
+ goto out_out;
+
+ if (out->hdr.status) {
+ err = mlx5_cmd_status_to_err(&out->hdr);
+ goto out_out;
+ }
+
+
+ caps->log_max_eq = out->hca_cap.log_max_eq & 0xf;
+ caps->max_cqes = 1 << out->hca_cap.log_max_cq_sz;
+ caps->max_wqes = 1 << out->hca_cap.log_max_qp_sz;
+ caps->max_sq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_sq);
+ caps->max_rq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_rq);
+ caps->flags = be64_to_cpu(out->hca_cap.flags);
+ caps->stat_rate_support = be16_to_cpu(out->hca_cap.stat_rate_support);
+ caps->log_max_msg = out->hca_cap.log_max_msg & 0x1f;
+ caps->num_ports = out->hca_cap.num_ports & 0xf;
+ caps->log_max_cq = out->hca_cap.log_max_cq & 0x1f;
+ if (caps->num_ports > MLX5_MAX_PORTS) {
+ mlx5_core_err(dev, "device has %d ports while the driver supports max %d ports\n",
+ caps->num_ports, MLX5_MAX_PORTS);
+ err = -EINVAL;
+ goto out_out;
+ }
+ caps->log_max_qp = out->hca_cap.log_max_qp & 0x1f;
+ caps->log_max_mkey = out->hca_cap.log_max_mkey & 0x3f;
+ caps->log_max_pd = out->hca_cap.log_max_pd & 0x1f;
+ caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f;
+ caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f;
+ caps->log_max_mcg = out->hca_cap.log_max_mcg;
+ caps->max_qp_mcg = be16_to_cpu(out->hca_cap.max_qp_mcg);
+ caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f);
+ caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f);
+ caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz;
+ t16 = be16_to_cpu(out->hca_cap.bf_log_bf_reg_size);
+ if (t16 & 0x8000) {
+ caps->bf_reg_size = 1 << (t16 & 0x1f);
+ caps->bf_regs_per_page = MLX5_BF_REGS_PER_PAGE;
+ } else {
+ caps->bf_reg_size = 0;
+ caps->bf_regs_per_page = 0;
+ }
+ caps->min_page_sz = ~(u32)((1 << out->hca_cap.log_pg_sz) - 1);
+
+ memset(&ctx_in, 0, sizeof(ctx_in));
+ memset(&ctx_out, 0, sizeof(ctx_out));
+ ctx_in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+ err = mlx5_cmd_exec(dev, &ctx_in, sizeof(ctx_in),
+ &ctx_out, sizeof(ctx_out));
+ if (err)
+ goto out_out;
+
+ if (ctx_out.hdr.status)
+ err = mlx5_cmd_status_to_err(&ctx_out.hdr);
+
+ caps->reserved_lkey = be32_to_cpu(ctx_out.reserved_lkey);
+
+out_out:
+ kfree(out);
+
+ return err;
+}
+
+int mlx5_cmd_init_hca(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_init_hca_mbox_in in;
+ struct mlx5_cmd_init_hca_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_INIT_HCA);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+
+int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_teardown_hca_mbox_in in;
+ struct mlx5_cmd_teardown_hca_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_TEARDOWN_HCA);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
new file mode 100644
index 000000000000..748f10a155c4
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/vmalloc.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+ MLX5_HEALTH_POLL_INTERVAL = 2 * HZ,
+ MAX_MISSES = 3,
+};
+
+enum {
+ MLX5_HEALTH_SYNDR_FW_ERR = 0x1,
+ MLX5_HEALTH_SYNDR_IRISC_ERR = 0x7,
+ MLX5_HEALTH_SYNDR_CRC_ERR = 0x9,
+ MLX5_HEALTH_SYNDR_FETCH_PCI_ERR = 0xa,
+ MLX5_HEALTH_SYNDR_HW_FTL_ERR = 0xb,
+ MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR = 0xc,
+ MLX5_HEALTH_SYNDR_EQ_ERR = 0xd,
+ MLX5_HEALTH_SYNDR_FFSER_ERR = 0xf,
+};
+
+static DEFINE_SPINLOCK(health_lock);
+
+static LIST_HEAD(health_list);
+static struct work_struct health_work;
+
+static health_handler_t reg_handler;
+int mlx5_register_health_report_handler(health_handler_t handler)
+{
+ spin_lock_irq(&health_lock);
+ if (reg_handler) {
+ spin_unlock_irq(&health_lock);
+ return -EEXIST;
+ }
+ reg_handler = handler;
+ spin_unlock_irq(&health_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(mlx5_register_health_report_handler);
+
+void mlx5_unregister_health_report_handler(void)
+{
+ spin_lock_irq(&health_lock);
+ reg_handler = NULL;
+ spin_unlock_irq(&health_lock);
+}
+EXPORT_SYMBOL(mlx5_unregister_health_report_handler);
+
+static void health_care(struct work_struct *work)
+{
+ struct mlx5_core_health *health, *n;
+ struct mlx5_core_dev *dev;
+ struct mlx5_priv *priv;
+ LIST_HEAD(tlist);
+
+ spin_lock_irq(&health_lock);
+ list_splice_init(&health_list, &tlist);
+
+ spin_unlock_irq(&health_lock);
+
+ list_for_each_entry_safe(health, n, &tlist, list) {
+ priv = container_of(health, struct mlx5_priv, health);
+ dev = container_of(priv, struct mlx5_core_dev, priv);
+ mlx5_core_warn(dev, "handling bad device here\n");
+ spin_lock_irq(&health_lock);
+ if (reg_handler)
+ reg_handler(dev->pdev, health->health,
+ sizeof(health->health));
+
+ list_del_init(&health->list);
+ spin_unlock_irq(&health_lock);
+ }
+}
+
+static const char *hsynd_str(u8 synd)
+{
+ switch (synd) {
+ case MLX5_HEALTH_SYNDR_FW_ERR:
+ return "firmware internal error";
+ case MLX5_HEALTH_SYNDR_IRISC_ERR:
+ return "irisc not responding";
+ case MLX5_HEALTH_SYNDR_CRC_ERR:
+ return "firmware CRC error";
+ case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR:
+ return "ICM fetch PCI error";
+ case MLX5_HEALTH_SYNDR_HW_FTL_ERR:
+ return "HW fatal error\n";
+ case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR:
+ return "async EQ buffer overrun";
+ case MLX5_HEALTH_SYNDR_EQ_ERR:
+ return "EQ error";
+ case MLX5_HEALTH_SYNDR_FFSER_ERR:
+ return "FFSER error";
+ default:
+ return "unrecognized error";
+ }
+}
+
+static u16 read_be16(__be16 __iomem *p)
+{
+ return swab16(readl((__force u16 __iomem *) p));
+}
+
+static u32 read_be32(__be32 __iomem *p)
+{
+ return swab32(readl((__force u32 __iomem *) p));
+}
+
+static void print_health_info(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+ struct health_buffer __iomem *h = health->health;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(h->assert_var); i++)
+ pr_info("assert_var[%d] 0x%08x\n", i, read_be32(h->assert_var + i));
+
+ pr_info("assert_exit_ptr 0x%08x\n", read_be32(&h->assert_exit_ptr));
+ pr_info("assert_callra 0x%08x\n", read_be32(&h->assert_callra));
+ pr_info("fw_ver 0x%08x\n", read_be32(&h->fw_ver));
+ pr_info("hw_id 0x%08x\n", read_be32(&h->hw_id));
+ pr_info("irisc_index %d\n", readb(&h->irisc_index));
+ pr_info("synd 0x%x: %s\n", readb(&h->synd), hsynd_str(readb(&h->synd)));
+ pr_info("ext_sync 0x%04x\n", read_be16(&h->ext_sync));
+}
+
+static void poll_health(unsigned long data)
+{
+ struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data;
+ struct mlx5_core_health *health = &dev->priv.health;
+ unsigned long next;
+ u32 count;
+
+ count = ioread32be(health->health_counter);
+ if (count == health->prev)
+ ++health->miss_counter;
+ else
+ health->miss_counter = 0;
+
+ health->prev = count;
+ if (health->miss_counter == MAX_MISSES) {
+ mlx5_core_err(dev, "device's health compromised\n");
+ print_health_info(dev);
+ spin_lock_irq(&health_lock);
+ list_add_tail(&health->list, &health_list);
+ spin_unlock_irq(&health_lock);
+
+ queue_work(mlx5_core_wq, &health_work);
+ } else {
+ get_random_bytes(&next, sizeof(next));
+ next %= HZ;
+ next += jiffies + MLX5_HEALTH_POLL_INTERVAL;
+ mod_timer(&health->timer, next);
+ }
+}
+
+void mlx5_start_health_poll(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+
+ INIT_LIST_HEAD(&health->list);
+ init_timer(&health->timer);
+ health->health = &dev->iseg->health;
+ health->health_counter = &dev->iseg->health_counter;
+
+ health->timer.data = (unsigned long)dev;
+ health->timer.function = poll_health;
+ health->timer.expires = round_jiffies(jiffies + MLX5_HEALTH_POLL_INTERVAL);
+ add_timer(&health->timer);
+}
+
+void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+
+ del_timer_sync(&health->timer);
+
+ spin_lock_irq(&health_lock);
+ if (!list_empty(&health->list))
+ list_del_init(&health->list);
+ spin_unlock_irq(&health_lock);
+}
+
+void mlx5_health_cleanup(void)
+{
+}
+
+void __init mlx5_health_init(void)
+{
+ INIT_WORK(&health_work, health_care);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mad.c b/drivers/net/ethernet/mellanox/mlx5/core/mad.c
new file mode 100644
index 000000000000..18d6fd5dd90b
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mad.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb,
+ u16 opmod, int port)
+{
+ struct mlx5_mad_ifc_mbox_in *in = NULL;
+ struct mlx5_mad_ifc_mbox_out *out = NULL;
+ int err;
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
+ if (!out) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MAD_IFC);
+ in->hdr.opmod = cpu_to_be16(opmod);
+ in->port = port;
+
+ memcpy(in->data, inb, sizeof(in->data));
+
+ err = mlx5_cmd_exec(dev, in, sizeof(*in), out, sizeof(*out));
+ if (err)
+ goto out;
+
+ if (out->hdr.status) {
+ err = mlx5_cmd_status_to_err(&out->hdr);
+ goto out;
+ }
+
+ memcpy(outb, out->data, sizeof(out->data));
+
+out:
+ kfree(out);
+ kfree(in);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_mad_ifc);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
new file mode 100644
index 000000000000..12242de2b0e3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io-mapping.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/debugfs.h>
+#include "mlx5_core.h"
+
+#define DRIVER_NAME "mlx5_core"
+#define DRIVER_VERSION "1.0"
+#define DRIVER_RELDATE "June 2013"
+
+MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+int mlx5_core_debug_mask;
+module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644);
+MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0");
+
+struct workqueue_struct *mlx5_core_wq;
+
+static int set_dma_caps(struct pci_dev *pdev)
+{
+ int err;
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n");
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");
+ return err;
+ }
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_warn(&pdev->dev,
+ "Warning: couldn't set 64-bit consistent PCI DMA mask.\n");
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev,
+ "Can't set consistent PCI DMA mask, aborting.\n");
+ return err;
+ }
+ }
+
+ dma_set_max_seg_size(&pdev->dev, 2u * 1024 * 1024 * 1024);
+ return err;
+}
+
+static int request_bar(struct pci_dev *pdev)
+{
+ int err = 0;
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ dev_err(&pdev->dev, "Missing registers BAR, aborting.\n");
+ return -ENODEV;
+ }
+
+ err = pci_request_regions(pdev, DRIVER_NAME);
+ if (err)
+ dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n");
+
+ return err;
+}
+
+static void release_bar(struct pci_dev *pdev)
+{
+ pci_release_regions(pdev);
+}
+
+static int mlx5_enable_msix(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+ int num_eqs = 1 << dev->caps.log_max_eq;
+ int nvec;
+ int err;
+ int i;
+
+ nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE;
+ nvec = min_t(int, nvec, num_eqs);
+ if (nvec <= MLX5_EQ_VEC_COMP_BASE)
+ return -ENOMEM;
+
+ table->msix_arr = kzalloc(nvec * sizeof(*table->msix_arr), GFP_KERNEL);
+ if (!table->msix_arr)
+ return -ENOMEM;
+
+ for (i = 0; i < nvec; i++)
+ table->msix_arr[i].entry = i;
+
+retry:
+ table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
+ err = pci_enable_msix(dev->pdev, table->msix_arr, nvec);
+ if (err <= 0) {
+ return err;
+ } else if (err > 2) {
+ nvec = err;
+ goto retry;
+ }
+
+ mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec);
+
+ return 0;
+}
+
+static void mlx5_disable_msix(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eq_table *table = &dev->priv.eq_table;
+
+ pci_disable_msix(dev->pdev);
+ kfree(table->msix_arr);
+}
+
+struct mlx5_reg_host_endianess {
+ u8 he;
+ u8 rsvd[15];
+};
+
+static int handle_hca_cap(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd_query_hca_cap_mbox_out *query_out = NULL;
+ struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL;
+ struct mlx5_cmd_query_hca_cap_mbox_in query_ctx;
+ struct mlx5_cmd_set_hca_cap_mbox_out set_out;
+ struct mlx5_profile *prof = dev->profile;
+ u64 flags;
+ int csum = 1;
+ int err;
+
+ memset(&query_ctx, 0, sizeof(query_ctx));
+ query_out = kzalloc(sizeof(*query_out), GFP_KERNEL);
+ if (!query_out)
+ return -ENOMEM;
+
+ set_ctx = kzalloc(sizeof(*set_ctx), GFP_KERNEL);
+ if (!set_ctx) {
+ err = -ENOMEM;
+ goto query_ex;
+ }
+
+ query_ctx.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP);
+ query_ctx.hdr.opmod = cpu_to_be16(0x1);
+ err = mlx5_cmd_exec(dev, &query_ctx, sizeof(query_ctx),
+ query_out, sizeof(*query_out));
+ if (err)
+ goto query_ex;
+
+ err = mlx5_cmd_status_to_err(&query_out->hdr);
+ if (err) {
+ mlx5_core_warn(dev, "query hca cap failed, %d\n", err);
+ goto query_ex;
+ }
+
+ memcpy(&set_ctx->hca_cap, &query_out->hca_cap,
+ sizeof(set_ctx->hca_cap));
+
+ if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) {
+ csum = !!prof->cmdif_csum;
+ flags = be64_to_cpu(set_ctx->hca_cap.flags);
+ if (csum)
+ flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+ else
+ flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+
+ set_ctx->hca_cap.flags = cpu_to_be64(flags);
+ }
+
+ if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE)
+ set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp;
+
+ memset(&set_out, 0, sizeof(set_out));
+ set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12);
+ set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP);
+ err = mlx5_cmd_exec(dev, set_ctx, sizeof(*set_ctx),
+ &set_out, sizeof(set_out));
+ if (err) {
+ mlx5_core_warn(dev, "set hca cap failed, %d\n", err);
+ goto query_ex;
+ }
+
+ err = mlx5_cmd_status_to_err(&set_out.hdr);
+ if (err)
+ goto query_ex;
+
+ if (!csum)
+ dev->cmd.checksum_disabled = 1;
+
+query_ex:
+ kfree(query_out);
+ kfree(set_ctx);
+
+ return err;
+}
+
+static int set_hca_ctrl(struct mlx5_core_dev *dev)
+{
+ struct mlx5_reg_host_endianess he_in;
+ struct mlx5_reg_host_endianess he_out;
+ int err;
+
+ memset(&he_in, 0, sizeof(he_in));
+ he_in.he = MLX5_SET_HOST_ENDIANNESS;
+ err = mlx5_core_access_reg(dev, &he_in, sizeof(he_in),
+ &he_out, sizeof(he_out),
+ MLX5_REG_HOST_ENDIANNESS, 0, 1);
+ return err;
+}
+
+int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
+{
+ struct mlx5_priv *priv = &dev->priv;
+ int err;
+
+ dev->pdev = pdev;
+ pci_set_drvdata(dev->pdev, dev);
+ strncpy(priv->name, dev_name(&pdev->dev), MLX5_MAX_NAME_LEN);
+ priv->name[MLX5_MAX_NAME_LEN - 1] = 0;
+
+ mutex_init(&priv->pgdir_mutex);
+ INIT_LIST_HEAD(&priv->pgdir_list);
+ spin_lock_init(&priv->mkey_lock);
+
+ priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root);
+ if (!priv->dbg_root)
+ return -ENOMEM;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
+ goto err_dbg;
+ }
+
+ err = request_bar(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "error requesting BARs, aborting.\n");
+ goto err_disable;
+ }
+
+ pci_set_master(pdev);
+
+ err = set_dma_caps(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed setting DMA capabilities mask, aborting\n");
+ goto err_clr_master;
+ }
+
+ dev->iseg_base = pci_resource_start(dev->pdev, 0);
+ dev->iseg = ioremap(dev->iseg_base, sizeof(*dev->iseg));
+ if (!dev->iseg) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed mapping initialization segment, aborting\n");
+ goto err_clr_master;
+ }
+ dev_info(&pdev->dev, "firmware version: %d.%d.%d\n", fw_rev_maj(dev),
+ fw_rev_min(dev), fw_rev_sub(dev));
+
+ err = mlx5_cmd_init(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed initializing command interface, aborting\n");
+ goto err_unmap;
+ }
+
+ mlx5_pagealloc_init(dev);
+ err = set_hca_ctrl(dev);
+ if (err) {
+ dev_err(&pdev->dev, "set_hca_ctrl failed\n");
+ goto err_pagealloc_cleanup;
+ }
+
+ err = handle_hca_cap(dev);
+ if (err) {
+ dev_err(&pdev->dev, "handle_hca_cap failed\n");
+ goto err_pagealloc_cleanup;
+ }
+
+ err = mlx5_satisfy_startup_pages(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to allocate startup pages\n");
+ goto err_pagealloc_cleanup;
+ }
+
+ err = mlx5_pagealloc_start(dev);
+ if (err) {
+ dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
+ goto err_reclaim_pages;
+ }
+
+ err = mlx5_cmd_init_hca(dev);
+ if (err) {
+ dev_err(&pdev->dev, "init hca failed\n");
+ goto err_pagealloc_stop;
+ }
+
+ mlx5_start_health_poll(dev);
+
+ err = mlx5_cmd_query_hca_cap(dev, &dev->caps);
+ if (err) {
+ dev_err(&pdev->dev, "query hca failed\n");
+ goto err_stop_poll;
+ }
+
+ err = mlx5_cmd_query_adapter(dev);
+ if (err) {
+ dev_err(&pdev->dev, "query adapter failed\n");
+ goto err_stop_poll;
+ }
+
+ err = mlx5_enable_msix(dev);
+ if (err) {
+ dev_err(&pdev->dev, "enable msix failed\n");
+ goto err_stop_poll;
+ }
+
+ err = mlx5_eq_init(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to initialize eq\n");
+ goto disable_msix;
+ }
+
+ err = mlx5_alloc_uuars(dev, &priv->uuari);
+ if (err) {
+ dev_err(&pdev->dev, "Failed allocating uar, aborting\n");
+ goto err_eq_cleanup;
+ }
+
+ err = mlx5_start_eqs(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to start pages and async EQs\n");
+ goto err_free_uar;
+ }
+
+ MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock);
+
+ mlx5_init_cq_table(dev);
+ mlx5_init_qp_table(dev);
+ mlx5_init_srq_table(dev);
+
+ return 0;
+
+err_free_uar:
+ mlx5_free_uuars(dev, &priv->uuari);
+
+err_eq_cleanup:
+ mlx5_eq_cleanup(dev);
+
+disable_msix:
+ mlx5_disable_msix(dev);
+
+err_stop_poll:
+ mlx5_stop_health_poll(dev);
+ mlx5_cmd_teardown_hca(dev);
+
+err_pagealloc_stop:
+ mlx5_pagealloc_stop(dev);
+
+err_reclaim_pages:
+ mlx5_reclaim_startup_pages(dev);
+
+err_pagealloc_cleanup:
+ mlx5_pagealloc_cleanup(dev);
+ mlx5_cmd_cleanup(dev);
+
+err_unmap:
+ iounmap(dev->iseg);
+
+err_clr_master:
+ pci_clear_master(dev->pdev);
+ release_bar(dev->pdev);
+
+err_disable:
+ pci_disable_device(dev->pdev);
+
+err_dbg:
+ debugfs_remove(priv->dbg_root);
+ return err;
+}
+EXPORT_SYMBOL(mlx5_dev_init);
+
+void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
+{
+ struct mlx5_priv *priv = &dev->priv;
+
+ mlx5_cleanup_srq_table(dev);
+ mlx5_cleanup_qp_table(dev);
+ mlx5_cleanup_cq_table(dev);
+ mlx5_stop_eqs(dev);
+ mlx5_free_uuars(dev, &priv->uuari);
+ mlx5_eq_cleanup(dev);
+ mlx5_disable_msix(dev);
+ mlx5_stop_health_poll(dev);
+ mlx5_cmd_teardown_hca(dev);
+ mlx5_pagealloc_stop(dev);
+ mlx5_reclaim_startup_pages(dev);
+ mlx5_pagealloc_cleanup(dev);
+ mlx5_cmd_cleanup(dev);
+ iounmap(dev->iseg);
+ pci_clear_master(dev->pdev);
+ release_bar(dev->pdev);
+ pci_disable_device(dev->pdev);
+ debugfs_remove(priv->dbg_root);
+}
+EXPORT_SYMBOL(mlx5_dev_cleanup);
+
+static int __init init(void)
+{
+ int err;
+
+ mlx5_register_debugfs();
+ mlx5_core_wq = create_singlethread_workqueue("mlx5_core_wq");
+ if (!mlx5_core_wq) {
+ err = -ENOMEM;
+ goto err_debug;
+ }
+ mlx5_health_init();
+
+ return 0;
+
+ mlx5_health_cleanup();
+err_debug:
+ mlx5_unregister_debugfs();
+ return err;
+}
+
+static void __exit cleanup(void)
+{
+ mlx5_health_cleanup();
+ destroy_workqueue(mlx5_core_wq);
+ mlx5_unregister_debugfs();
+}
+
+module_init(init);
+module_exit(cleanup);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
new file mode 100644
index 000000000000..44837640bd7c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_verbs.h>
+#include "mlx5_core.h"
+
+struct mlx5_attach_mcg_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ __be32 qpn;
+ __be32 rsvd;
+ u8 gid[16];
+};
+
+struct mlx5_attach_mcg_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ u8 rsvf[8];
+};
+
+struct mlx5_detach_mcg_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ __be32 qpn;
+ __be32 rsvd;
+ u8 gid[16];
+};
+
+struct mlx5_detach_mcg_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ u8 rsvf[8];
+};
+
+int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn)
+{
+ struct mlx5_attach_mcg_mbox_in in;
+ struct mlx5_attach_mcg_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ATTACH_TO_MCG);
+ memcpy(in.gid, mgid, sizeof(*mgid));
+ in.qpn = cpu_to_be32(qpn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_attach_mcg);
+
+int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn)
+{
+ struct mlx5_detach_mcg_mbox_in in;
+ struct mlx5_detach_mcg_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETACH_FROM_MCG);
+ memcpy(in.gid, mgid, sizeof(*mgid));
+ in.qpn = cpu_to_be32(qpn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_detach_mcg);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
new file mode 100644
index 000000000000..68b74e1ae1b0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_CORE_H__
+#define __MLX5_CORE_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+extern int mlx5_core_debug_mask;
+
+#define mlx5_core_dbg(dev, format, arg...) \
+pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \
+ current->pid, ##arg)
+
+#define mlx5_core_dbg_mask(dev, mask, format, arg...) \
+do { \
+ if ((mask) & mlx5_core_debug_mask) \
+ pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, \
+ __func__, __LINE__, current->pid, ##arg); \
+} while (0)
+
+#define mlx5_core_err(dev, format, arg...) \
+pr_err("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \
+ current->pid, ##arg)
+
+#define mlx5_core_warn(dev, format, arg...) \
+pr_warn("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__, \
+ current->pid, ##arg)
+
+enum {
+ MLX5_CMD_DATA, /* print command payload only */
+ MLX5_CMD_TIME, /* print command execution time */
+};
+
+
+int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
+ struct mlx5_caps *caps);
+int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev);
+int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
+int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
+
+#endif /* __MLX5_CORE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
new file mode 100644
index 000000000000..5b44e2e46daf
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+ struct mlx5_create_mkey_mbox_in *in, int inlen)
+{
+ struct mlx5_create_mkey_mbox_out out;
+ int err;
+ u8 key;
+
+ memset(&out, 0, sizeof(out));
+ spin_lock(&dev->priv.mkey_lock);
+ key = dev->priv.mkey_key++;
+ spin_unlock(&dev->priv.mkey_lock);
+ in->seg.qpn_mkey7_0 |= cpu_to_be32(key);
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY);
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ if (err) {
+ mlx5_core_dbg(dev, "cmd exec faile %d\n", err);
+ return err;
+ }
+
+ if (out.hdr.status) {
+ mlx5_core_dbg(dev, "status %d\n", out.hdr.status);
+ return mlx5_cmd_status_to_err(&out.hdr);
+ }
+
+ mr->key = mlx5_idx_to_mkey(be32_to_cpu(out.mkey) & 0xffffff) | key;
+ mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", be32_to_cpu(out.mkey), key, mr->key);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_mkey);
+
+int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
+{
+ struct mlx5_destroy_mkey_mbox_in in;
+ struct mlx5_destroy_mkey_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY);
+ in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_mkey);
+
+int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+ struct mlx5_query_mkey_mbox_out *out, int outlen)
+{
+ struct mlx5_destroy_mkey_mbox_in in;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(out, 0, outlen);
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY);
+ in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+ if (err)
+ return err;
+
+ if (out->hdr.status)
+ return mlx5_cmd_status_to_err(&out->hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_mkey);
+
+int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+ u32 *mkey)
+{
+ struct mlx5_query_special_ctxs_mbox_in in;
+ struct mlx5_query_special_ctxs_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ *mkey = be32_to_cpu(out.dump_fill_mkey);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_dump_fill_mkey);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
new file mode 100644
index 000000000000..f0bf46339b28
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+ MLX5_PAGES_CANT_GIVE = 0,
+ MLX5_PAGES_GIVE = 1,
+ MLX5_PAGES_TAKE = 2
+};
+
+struct mlx5_pages_req {
+ struct mlx5_core_dev *dev;
+ u32 func_id;
+ s16 npages;
+ struct work_struct work;
+};
+
+struct fw_page {
+ struct rb_node rb_node;
+ u64 addr;
+ struct page *page;
+ u16 func_id;
+};
+
+struct mlx5_query_pages_inbox {
+ struct mlx5_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct mlx5_query_pages_outbox {
+ struct mlx5_outbox_hdr hdr;
+ u8 reserved[2];
+ __be16 func_id;
+ __be16 init_pages;
+ __be16 num_pages;
+};
+
+struct mlx5_manage_pages_inbox {
+ struct mlx5_inbox_hdr hdr;
+ __be16 rsvd0;
+ __be16 func_id;
+ __be16 rsvd1;
+ __be16 num_entries;
+ u8 rsvd2[16];
+ __be64 pas[0];
+};
+
+struct mlx5_manage_pages_outbox {
+ struct mlx5_outbox_hdr hdr;
+ u8 rsvd0[2];
+ __be16 num_entries;
+ u8 rsvd1[20];
+ __be64 pas[0];
+};
+
+static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)
+{
+ struct rb_root *root = &dev->priv.page_root;
+ struct rb_node **new = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct fw_page *nfp;
+ struct fw_page *tfp;
+
+ while (*new) {
+ parent = *new;
+ tfp = rb_entry(parent, struct fw_page, rb_node);
+ if (tfp->addr < addr)
+ new = &parent->rb_left;
+ else if (tfp->addr > addr)
+ new = &parent->rb_right;
+ else
+ return -EEXIST;
+ }
+
+ nfp = kmalloc(sizeof(*nfp), GFP_KERNEL);
+ if (!nfp)
+ return -ENOMEM;
+
+ nfp->addr = addr;
+ nfp->page = page;
+ nfp->func_id = func_id;
+
+ rb_link_node(&nfp->rb_node, parent, new);
+ rb_insert_color(&nfp->rb_node, root);
+
+ return 0;
+}
+
+static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
+{
+ struct rb_root *root = &dev->priv.page_root;
+ struct rb_node *tmp = root->rb_node;
+ struct page *result = NULL;
+ struct fw_page *tfp;
+
+ while (tmp) {
+ tfp = rb_entry(tmp, struct fw_page, rb_node);
+ if (tfp->addr < addr) {
+ tmp = tmp->rb_left;
+ } else if (tfp->addr > addr) {
+ tmp = tmp->rb_right;
+ } else {
+ rb_erase(&tfp->rb_node, root);
+ result = tfp->page;
+ kfree(tfp);
+ break;
+ }
+ }
+
+ return result;
+}
+
+static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
+ s16 *pages, s16 *init_pages)
+{
+ struct mlx5_query_pages_inbox in;
+ struct mlx5_query_pages_outbox out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ if (pages)
+ *pages = be16_to_cpu(out.num_pages);
+ if (init_pages)
+ *init_pages = be16_to_cpu(out.init_pages);
+ *func_id = be16_to_cpu(out.func_id);
+
+ return err;
+}
+
+static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
+ int notify_fail)
+{
+ struct mlx5_manage_pages_inbox *in;
+ struct mlx5_manage_pages_outbox out;
+ struct page *page;
+ int inlen;
+ u64 addr;
+ int err;
+ int i;
+
+ inlen = sizeof(*in) + npages * sizeof(in->pas[0]);
+ in = mlx5_vzalloc(inlen);
+ if (!in) {
+ mlx5_core_warn(dev, "vzalloc failed %d\n", inlen);
+ return -ENOMEM;
+ }
+ memset(&out, 0, sizeof(out));
+
+ for (i = 0; i < npages; i++) {
+ page = alloc_page(GFP_HIGHUSER);
+ if (!page) {
+ err = -ENOMEM;
+ mlx5_core_warn(dev, "failed to allocate page\n");
+ goto out_alloc;
+ }
+ addr = dma_map_page(&dev->pdev->dev, page, 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(&dev->pdev->dev, addr)) {
+ mlx5_core_warn(dev, "failed dma mapping page\n");
+ __free_page(page);
+ err = -ENOMEM;
+ goto out_alloc;
+ }
+ err = insert_page(dev, addr, page, func_id);
+ if (err) {
+ mlx5_core_err(dev, "failed to track allocated page\n");
+ dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(page);
+ err = -ENOMEM;
+ goto out_alloc;
+ }
+ in->pas[i] = cpu_to_be64(addr);
+ }
+
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+ in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE);
+ in->func_id = cpu_to_be16(func_id);
+ in->num_entries = cpu_to_be16(npages);
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ mlx5_core_dbg(dev, "err %d\n", err);
+ if (err) {
+ mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", func_id, npages, err);
+ goto out_alloc;
+ }
+ dev->priv.fw_pages += npages;
+
+ if (out.hdr.status) {
+ err = mlx5_cmd_status_to_err(&out.hdr);
+ if (err) {
+ mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", func_id, npages, out.hdr.status);
+ goto out_alloc;
+ }
+ }
+
+ mlx5_core_dbg(dev, "err %d\n", err);
+
+ goto out_free;
+
+out_alloc:
+ if (notify_fail) {
+ memset(in, 0, inlen);
+ memset(&out, 0, sizeof(out));
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+ in->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE);
+ if (mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out)))
+ mlx5_core_warn(dev, "\n");
+ }
+ for (i--; i >= 0; i--) {
+ addr = be64_to_cpu(in->pas[i]);
+ page = remove_page(dev, addr);
+ if (!page) {
+ mlx5_core_err(dev, "BUG: can't remove page at addr 0x%llx\n",
+ addr);
+ continue;
+ }
+ dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(page);
+ }
+
+out_free:
+ mlx5_vfree(in);
+ return err;
+}
+
+static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
+ int *nclaimed)
+{
+ struct mlx5_manage_pages_inbox in;
+ struct mlx5_manage_pages_outbox *out;
+ struct page *page;
+ int num_claimed;
+ int outlen;
+ u64 addr;
+ int err;
+ int i;
+
+ memset(&in, 0, sizeof(in));
+ outlen = sizeof(*out) + npages * sizeof(out->pas[0]);
+ out = mlx5_vzalloc(outlen);
+ if (!out)
+ return -ENOMEM;
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+ in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE);
+ in.func_id = cpu_to_be16(func_id);
+ in.num_entries = cpu_to_be16(npages);
+ mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+ if (err) {
+ mlx5_core_err(dev, "failed recliaming pages\n");
+ goto out_free;
+ }
+ dev->priv.fw_pages -= npages;
+
+ if (out->hdr.status) {
+ err = mlx5_cmd_status_to_err(&out->hdr);
+ goto out_free;
+ }
+
+ num_claimed = be16_to_cpu(out->num_entries);
+ if (nclaimed)
+ *nclaimed = num_claimed;
+
+ for (i = 0; i < num_claimed; i++) {
+ addr = be64_to_cpu(out->pas[i]);
+ page = remove_page(dev, addr);
+ if (!page) {
+ mlx5_core_warn(dev, "FW reported unknown DMA address 0x%llx\n", addr);
+ } else {
+ dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(page);
+ }
+ }
+
+out_free:
+ mlx5_vfree(out);
+ return err;
+}
+
+static void pages_work_handler(struct work_struct *work)
+{
+ struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work);
+ struct mlx5_core_dev *dev = req->dev;
+ int err = 0;
+
+ if (req->npages < 0)
+ err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL);
+ else if (req->npages > 0)
+ err = give_pages(dev, req->func_id, req->npages, 1);
+
+ if (err)
+ mlx5_core_warn(dev, "%s fail %d\n", req->npages < 0 ?
+ "reclaim" : "give", err);
+
+ kfree(req);
+}
+
+void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
+ s16 npages)
+{
+ struct mlx5_pages_req *req;
+
+ req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ if (!req) {
+ mlx5_core_warn(dev, "failed to allocate pages request\n");
+ return;
+ }
+
+ req->dev = dev;
+ req->func_id = func_id;
+ req->npages = npages;
+ INIT_WORK(&req->work, pages_work_handler);
+ queue_work(dev->priv.pg_wq, &req->work);
+}
+
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+{
+ s16 uninitialized_var(init_pages);
+ u16 uninitialized_var(func_id);
+ int err;
+
+ err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+ if (err)
+ return err;
+
+ mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
+
+ return give_pages(dev, func_id, init_pages, 0);
+}
+
+static int optimal_reclaimed_pages(void)
+{
+ struct mlx5_cmd_prot_block *block;
+ struct mlx5_cmd_layout *lay;
+ int ret;
+
+ ret = (sizeof(lay->in) + sizeof(block->data) -
+ sizeof(struct mlx5_manage_pages_outbox)) / 8;
+
+ return ret;
+}
+
+int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
+{
+ unsigned long end = jiffies + msecs_to_jiffies(5000);
+ struct fw_page *fwp;
+ struct rb_node *p;
+ int err;
+
+ do {
+ p = rb_first(&dev->priv.page_root);
+ if (p) {
+ fwp = rb_entry(p, struct fw_page, rb_node);
+ err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL);
+ if (err) {
+ mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err);
+ return err;
+ }
+ }
+ if (time_after(jiffies, end)) {
+ mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
+ break;
+ }
+ } while (p);
+
+ return 0;
+}
+
+void mlx5_pagealloc_init(struct mlx5_core_dev *dev)
+{
+ dev->priv.page_root = RB_ROOT;
+}
+
+void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
+{
+ /* nothing */
+}
+
+int mlx5_pagealloc_start(struct mlx5_core_dev *dev)
+{
+ dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
+ if (!dev->priv.pg_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
+{
+ destroy_workqueue(dev->priv.pg_wq);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pd.c b/drivers/net/ethernet/mellanox/mlx5/core/pd.c
new file mode 100644
index 000000000000..790da5c4ca4f
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pd.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+struct mlx5_alloc_pd_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct mlx5_alloc_pd_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ __be32 pdn;
+ u8 rsvd[4];
+};
+
+struct mlx5_dealloc_pd_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ __be32 pdn;
+ u8 rsvd[4];
+};
+
+struct mlx5_dealloc_pd_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn)
+{
+ struct mlx5_alloc_pd_mbox_in in;
+ struct mlx5_alloc_pd_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_PD);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ *pdn = be32_to_cpu(out.pdn) & 0xffffff;
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_alloc_pd);
+
+int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn)
+{
+ struct mlx5_dealloc_pd_mbox_in in;
+ struct mlx5_dealloc_pd_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_PD);
+ in.pdn = cpu_to_be32(pdn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_dealloc_pd);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
new file mode 100644
index 000000000000..f6afe7b5a675
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
+ int size_in, void *data_out, int size_out,
+ u16 reg_num, int arg, int write)
+{
+ struct mlx5_access_reg_mbox_in *in = NULL;
+ struct mlx5_access_reg_mbox_out *out = NULL;
+ int err = -ENOMEM;
+
+ in = mlx5_vzalloc(sizeof(*in) + size_in);
+ if (!in)
+ return -ENOMEM;
+
+ out = mlx5_vzalloc(sizeof(*out) + size_out);
+ if (!out)
+ goto ex1;
+
+ memcpy(in->data, data_in, size_in);
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG);
+ in->hdr.opmod = cpu_to_be16(!write);
+ in->arg = cpu_to_be32(arg);
+ in->register_id = cpu_to_be16(reg_num);
+ err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out,
+ sizeof(out) + size_out);
+ if (err)
+ goto ex2;
+
+ if (out->hdr.status)
+ err = mlx5_cmd_status_to_err(&out->hdr);
+
+ if (!err)
+ memcpy(data_out, out->data, size_out);
+
+ex2:
+ mlx5_vfree(out);
+ex1:
+ mlx5_vfree(in);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
+
+
+struct mlx5_reg_pcap {
+ u8 rsvd0;
+ u8 port_num;
+ u8 rsvd1[2];
+ __be32 caps_127_96;
+ __be32 caps_95_64;
+ __be32 caps_63_32;
+ __be32 caps_31_0;
+};
+
+int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps)
+{
+ struct mlx5_reg_pcap in;
+ struct mlx5_reg_pcap out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ in.caps_127_96 = cpu_to_be32(caps);
+ in.port_num = port_num;
+
+ err = mlx5_core_access_reg(dev, &in, sizeof(in), &out,
+ sizeof(out), MLX5_REG_PCAP, 0, 1);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
new file mode 100644
index 000000000000..54faf8bfcaf4
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+
+void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type)
+{
+ struct mlx5_qp_table *table = &dev->priv.qp_table;
+ struct mlx5_core_qp *qp;
+
+ spin_lock(&table->lock);
+
+ qp = radix_tree_lookup(&table->tree, qpn);
+ if (qp)
+ atomic_inc(&qp->refcount);
+
+ spin_unlock(&table->lock);
+
+ if (!qp) {
+ mlx5_core_warn(dev, "Async event for bogus QP 0x%x\n", qpn);
+ return;
+ }
+
+ qp->event(qp, event_type);
+
+ if (atomic_dec_and_test(&qp->refcount))
+ complete(&qp->free);
+}
+
+int mlx5_core_create_qp(struct mlx5_core_dev *dev,
+ struct mlx5_core_qp *qp,
+ struct mlx5_create_qp_mbox_in *in,
+ int inlen)
+{
+ struct mlx5_qp_table *table = &dev->priv.qp_table;
+ struct mlx5_create_qp_mbox_out out;
+ struct mlx5_destroy_qp_mbox_in din;
+ struct mlx5_destroy_qp_mbox_out dout;
+ int err;
+
+ memset(&dout, 0, sizeof(dout));
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP);
+
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ if (err) {
+ mlx5_core_warn(dev, "ret %d", err);
+ return err;
+ }
+
+ if (out.hdr.status) {
+ pr_warn("current num of QPs 0x%x\n", atomic_read(&dev->num_qps));
+ return mlx5_cmd_status_to_err(&out.hdr);
+ }
+
+ qp->qpn = be32_to_cpu(out.qpn) & 0xffffff;
+ mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn);
+
+ spin_lock_irq(&table->lock);
+ err = radix_tree_insert(&table->tree, qp->qpn, qp);
+ spin_unlock_irq(&table->lock);
+ if (err) {
+ mlx5_core_warn(dev, "err %d", err);
+ goto err_cmd;
+ }
+
+ err = mlx5_debug_qp_add(dev, qp);
+ if (err)
+ mlx5_core_dbg(dev, "failed adding QP 0x%x to debug file system\n",
+ qp->qpn);
+
+ qp->pid = current->pid;
+ atomic_set(&qp->refcount, 1);
+ atomic_inc(&dev->num_qps);
+ init_completion(&qp->free);
+
+ return 0;
+
+err_cmd:
+ memset(&din, 0, sizeof(din));
+ memset(&dout, 0, sizeof(dout));
+ din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
+ din.qpn = cpu_to_be32(qp->qpn);
+ mlx5_cmd_exec(dev, &din, sizeof(din), &out, sizeof(dout));
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_create_qp);
+
+int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,
+ struct mlx5_core_qp *qp)
+{
+ struct mlx5_destroy_qp_mbox_in in;
+ struct mlx5_destroy_qp_mbox_out out;
+ struct mlx5_qp_table *table = &dev->priv.qp_table;
+ unsigned long flags;
+ int err;
+
+ mlx5_debug_qp_remove(dev, qp);
+
+ spin_lock_irqsave(&table->lock, flags);
+ radix_tree_delete(&table->tree, qp->qpn);
+ spin_unlock_irqrestore(&table->lock, flags);
+
+ if (atomic_dec_and_test(&qp->refcount))
+ complete(&qp->free);
+ wait_for_completion(&qp->free);
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
+ in.qpn = cpu_to_be32(qp->qpn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ atomic_dec(&dev->num_qps);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_destroy_qp);
+
+int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state,
+ enum mlx5_qp_state new_state,
+ struct mlx5_modify_qp_mbox_in *in, int sqd_event,
+ struct mlx5_core_qp *qp)
+{
+ static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = {
+ [MLX5_QP_STATE_RST] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_RST2INIT_QP,
+ },
+ [MLX5_QP_STATE_INIT] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_INIT2INIT_QP,
+ [MLX5_QP_STATE_RTR] = MLX5_CMD_OP_INIT2RTR_QP,
+ },
+ [MLX5_QP_STATE_RTR] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTR2RTS_QP,
+ },
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTS2RTS_QP,
+ [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_RTS2SQD_QP,
+ },
+ [MLX5_QP_STATE_SQD] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQD2RTS_QP,
+ [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_SQD2SQD_QP,
+ },
+ [MLX5_QP_STATE_SQER] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQERR2RTS_QP,
+ },
+ [MLX5_QP_STATE_ERR] = {
+ [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
+ [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ }
+ };
+
+ struct mlx5_modify_qp_mbox_out out;
+ int err = 0;
+ u16 op;
+
+ if (cur_state >= MLX5_QP_NUM_STATE || new_state >= MLX5_QP_NUM_STATE ||
+ !optab[cur_state][new_state])
+ return -EINVAL;
+
+ memset(&out, 0, sizeof(out));
+ op = optab[cur_state][new_state];
+ in->hdr.opcode = cpu_to_be16(op);
+ in->qpn = cpu_to_be32(qp->qpn);
+ err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ return mlx5_cmd_status_to_err(&out.hdr);
+}
+EXPORT_SYMBOL_GPL(mlx5_core_qp_modify);
+
+void mlx5_init_qp_table(struct mlx5_core_dev *dev)
+{
+ struct mlx5_qp_table *table = &dev->priv.qp_table;
+
+ spin_lock_init(&table->lock);
+ INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+ mlx5_qp_debugfs_init(dev);
+}
+
+void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev)
+{
+ mlx5_qp_debugfs_cleanup(dev);
+}
+
+int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
+ struct mlx5_query_qp_mbox_out *out, int outlen)
+{
+ struct mlx5_query_qp_mbox_in in;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(out, 0, outlen);
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_QP);
+ in.qpn = cpu_to_be32(qp->qpn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+ if (err)
+ return err;
+
+ if (out->hdr.status)
+ return mlx5_cmd_status_to_err(&out->hdr);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_qp_query);
+
+int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn)
+{
+ struct mlx5_alloc_xrcd_mbox_in in;
+ struct mlx5_alloc_xrcd_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_XRCD);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+ else
+ *xrcdn = be32_to_cpu(out.xrcdn);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_xrcd_alloc);
+
+int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn)
+{
+ struct mlx5_dealloc_xrcd_mbox_in in;
+ struct mlx5_dealloc_xrcd_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_XRCD);
+ in.xrcdn = cpu_to_be32(xrcdn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
new file mode 100644
index 000000000000..38bce93f8314
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/srq.h>
+#include <rdma/ib_verbs.h>
+#include "mlx5_core.h"
+
+void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
+{
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+ struct mlx5_core_srq *srq;
+
+ spin_lock(&table->lock);
+
+ srq = radix_tree_lookup(&table->tree, srqn);
+ if (srq)
+ atomic_inc(&srq->refcount);
+
+ spin_unlock(&table->lock);
+
+ if (!srq) {
+ mlx5_core_warn(dev, "Async event for bogus SRQ 0x%08x\n", srqn);
+ return;
+ }
+
+ srq->event(srq, event_type);
+
+ if (atomic_dec_and_test(&srq->refcount))
+ complete(&srq->free);
+}
+
+struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
+{
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+ struct mlx5_core_srq *srq;
+
+ spin_lock(&table->lock);
+
+ srq = radix_tree_lookup(&table->tree, srqn);
+ if (srq)
+ atomic_inc(&srq->refcount);
+
+ spin_unlock(&table->lock);
+
+ return srq;
+}
+EXPORT_SYMBOL(mlx5_core_get_srq);
+
+int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in, int inlen)
+{
+ struct mlx5_create_srq_mbox_out out;
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+ struct mlx5_destroy_srq_mbox_in din;
+ struct mlx5_destroy_srq_mbox_out dout;
+ int err;
+
+ memset(&out, 0, sizeof(out));
+ in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ);
+ err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ srq->srqn = be32_to_cpu(out.srqn) & 0xffffff;
+
+ atomic_set(&srq->refcount, 1);
+ init_completion(&srq->free);
+
+ spin_lock_irq(&table->lock);
+ err = radix_tree_insert(&table->tree, srq->srqn, srq);
+ spin_unlock_irq(&table->lock);
+ if (err) {
+ mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn);
+ goto err_cmd;
+ }
+
+ return 0;
+
+err_cmd:
+ memset(&din, 0, sizeof(din));
+ memset(&dout, 0, sizeof(dout));
+ din.srqn = cpu_to_be32(srq->srqn);
+ din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
+ mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout));
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_srq);
+
+int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
+{
+ struct mlx5_destroy_srq_mbox_in in;
+ struct mlx5_destroy_srq_mbox_out out;
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+ struct mlx5_core_srq *tmp;
+ int err;
+
+ spin_lock_irq(&table->lock);
+ tmp = radix_tree_delete(&table->tree, srq->srqn);
+ spin_unlock_irq(&table->lock);
+ if (!tmp) {
+ mlx5_core_warn(dev, "srq 0x%x not found in tree\n", srq->srqn);
+ return -EINVAL;
+ }
+ if (tmp != srq) {
+ mlx5_core_warn(dev, "corruption on srqn 0x%x\n", srq->srqn);
+ return -EINVAL;
+ }
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
+ in.srqn = cpu_to_be32(srq->srqn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ if (atomic_dec_and_test(&srq->refcount))
+ complete(&srq->free);
+ wait_for_completion(&srq->free);
+
+ return 0;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_srq);
+
+int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_query_srq_mbox_out *out)
+{
+ struct mlx5_query_srq_mbox_in in;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(out, 0, sizeof(*out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ);
+ in.srqn = cpu_to_be32(srq->srqn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+ if (err)
+ return err;
+
+ if (out->hdr.status)
+ return mlx5_cmd_status_to_err(&out->hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_srq);
+
+int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ u16 lwm, int is_srq)
+{
+ struct mlx5_arm_srq_mbox_in in;
+ struct mlx5_arm_srq_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ);
+ in.hdr.opmod = cpu_to_be16(!!is_srq);
+ in.srqn = cpu_to_be32(srq->srqn);
+ in.lwm = cpu_to_be16(lwm);
+
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ return err;
+
+ if (out.hdr.status)
+ return mlx5_cmd_status_to_err(&out.hdr);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_arm_srq);
+
+void mlx5_init_srq_table(struct mlx5_core_dev *dev)
+{
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+
+ spin_lock_init(&table->lock);
+ INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+}
+
+void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev)
+{
+ /* nothing */
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
new file mode 100644
index 000000000000..71d4a3937200
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+ NUM_DRIVER_UARS = 4,
+ NUM_LOW_LAT_UUARS = 4,
+};
+
+
+struct mlx5_alloc_uar_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct mlx5_alloc_uar_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ __be32 uarn;
+ u8 rsvd[4];
+};
+
+struct mlx5_free_uar_mbox_in {
+ struct mlx5_inbox_hdr hdr;
+ __be32 uarn;
+ u8 rsvd[4];
+};
+
+struct mlx5_free_uar_mbox_out {
+ struct mlx5_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn)
+{
+ struct mlx5_alloc_uar_mbox_in in;
+ struct mlx5_alloc_uar_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_UAR);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ goto ex;
+
+ if (out.hdr.status) {
+ err = mlx5_cmd_status_to_err(&out.hdr);
+ goto ex;
+ }
+
+ *uarn = be32_to_cpu(out.uarn) & 0xffffff;
+
+ex:
+ return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_alloc_uar);
+
+int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn)
+{
+ struct mlx5_free_uar_mbox_in in;
+ struct mlx5_free_uar_mbox_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_UAR);
+ in.uarn = cpu_to_be32(uarn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err)
+ goto ex;
+
+ if (out.hdr.status)
+ err = mlx5_cmd_status_to_err(&out.hdr);
+
+ex:
+ return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_free_uar);
+
+static int need_uuar_lock(int uuarn)
+{
+ int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
+
+ if (uuarn == 0 || tot_uuars - NUM_LOW_LAT_UUARS)
+ return 0;
+
+ return 1;
+}
+
+int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
+{
+ int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
+ struct mlx5_bf *bf;
+ phys_addr_t addr;
+ int err;
+ int i;
+
+ uuari->num_uars = NUM_DRIVER_UARS;
+ uuari->num_low_latency_uuars = NUM_LOW_LAT_UUARS;
+
+ mutex_init(&uuari->lock);
+ uuari->uars = kcalloc(uuari->num_uars, sizeof(*uuari->uars), GFP_KERNEL);
+ if (!uuari->uars)
+ return -ENOMEM;
+
+ uuari->bfs = kcalloc(tot_uuars, sizeof(*uuari->bfs), GFP_KERNEL);
+ if (!uuari->bfs) {
+ err = -ENOMEM;
+ goto out_uars;
+ }
+
+ uuari->bitmap = kcalloc(BITS_TO_LONGS(tot_uuars), sizeof(*uuari->bitmap),
+ GFP_KERNEL);
+ if (!uuari->bitmap) {
+ err = -ENOMEM;
+ goto out_bfs;
+ }
+
+ uuari->count = kcalloc(tot_uuars, sizeof(*uuari->count), GFP_KERNEL);
+ if (!uuari->count) {
+ err = -ENOMEM;
+ goto out_bitmap;
+ }
+
+ for (i = 0; i < uuari->num_uars; i++) {
+ err = mlx5_cmd_alloc_uar(dev, &uuari->uars[i].index);
+ if (err)
+ goto out_count;
+
+ addr = dev->iseg_base + ((phys_addr_t)(uuari->uars[i].index) << PAGE_SHIFT);
+ uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
+ if (!uuari->uars[i].map) {
+ mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+ goto out_count;
+ }
+ mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
+ uuari->uars[i].index, uuari->uars[i].map);
+ }
+
+ for (i = 0; i < tot_uuars; i++) {
+ bf = &uuari->bfs[i];
+
+ bf->buf_size = dev->caps.bf_reg_size / 2;
+ bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE];
+ bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map;
+ bf->reg = NULL; /* Add WC support */
+ bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.bf_reg_size +
+ MLX5_BF_OFFSET;
+ bf->need_lock = need_uuar_lock(i);
+ spin_lock_init(&bf->lock);
+ spin_lock_init(&bf->lock32);
+ bf->uuarn = i;
+ }
+
+ return 0;
+
+out_count:
+ for (i--; i >= 0; i--) {
+ iounmap(uuari->uars[i].map);
+ mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+ }
+ kfree(uuari->count);
+
+out_bitmap:
+ kfree(uuari->bitmap);
+
+out_bfs:
+ kfree(uuari->bfs);
+
+out_uars:
+ kfree(uuari->uars);
+ return err;
+}
+
+int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
+{
+ int i = uuari->num_uars;
+
+ for (i--; i >= 0; i--) {
+ iounmap(uuari->uars[i].map);
+ mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+ }
+
+ kfree(uuari->count);
+ kfree(uuari->bitmap);
+ kfree(uuari->bfs);
+ kfree(uuari->uars);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/octeon/Kconfig b/drivers/net/ethernet/octeon/Kconfig
index 3de52ffd2872..a7aa28054cc1 100644
--- a/drivers/net/ethernet/octeon/Kconfig
+++ b/drivers/net/ethernet/octeon/Kconfig
@@ -4,7 +4,7 @@
config OCTEON_MGMT_ETHERNET
tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
select PHYLIB
select MDIO_OCTEON
default y
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 1df0ff3839e8..3df56840a3b9 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -1239,6 +1239,8 @@ static int vnet_port_remove(struct vio_dev *vdev)
dev_set_drvdata(&vdev->dev, NULL);
kfree(port);
+
+ unregister_netdev(vp->dev);
}
return 0;
}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3a316b30089f..342561ad3158 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -135,7 +135,7 @@ config MDIO_GPIO
config MDIO_OCTEON
tristate "Support for MDIO buses on Octeon SOCs"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
default y
help
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 42d670a468f8..3d2a90a62649 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -902,7 +902,6 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
struct scatterlist sg;
struct virtio_net_ctrl_mq s;
struct net_device *dev = vi->dev;
- int i;
if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
return 0;
@@ -916,10 +915,8 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
queue_pairs);
return -EINVAL;
} else {
- for (i = vi->curr_queue_pairs; i < queue_pairs; i++)
- if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
- schedule_delayed_work(&vi->refill, 0);
vi->curr_queue_pairs = queue_pairs;
+ schedule_delayed_work(&vi->refill, 0);
}
return 0;
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
index 00a71ebb5cac..9f7fe21580bb 100644
--- a/drivers/rapidio/switches/idt_gen2.c
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -16,6 +16,8 @@
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+
+#include <asm/page.h>
#include "../rio.h"
#define LOCAL_RTE_CONF_DESTID_SEL 0x010070
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 022dc635d01e..3cd85a638afa 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -762,13 +762,6 @@ static void rproc_resource_cleanup(struct rproc *rproc)
kfree(entry);
}
- /* clean up carveout allocations */
- list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
- dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma);
- list_del(&entry->node);
- kfree(entry);
- }
-
/* clean up iommu mapping entries */
list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
size_t unmapped;
@@ -783,6 +776,13 @@ static void rproc_resource_cleanup(struct rproc *rproc)
list_del(&entry->node);
kfree(entry);
}
+
+ /* clean up carveout allocations */
+ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+ dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma);
+ list_del(&entry->node);
+ kfree(entry);
+ }
}
/*
@@ -815,18 +815,17 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
}
rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
+ ret = -EINVAL;
/* look for the resource table */
table = rproc_find_rsc_table(rproc, fw, &tablesz);
if (!table) {
- ret = -EINVAL;
goto clean_up;
}
/* Verify that resource table in loaded fw is unchanged */
if (rproc->table_csum != crc32(0, table, tablesz)) {
dev_err(dev, "resource checksum failed, fw changed?\n");
- ret = -EINVAL;
goto clean_up;
}
@@ -852,8 +851,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
* copy this information to device memory.
*/
loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
- if (!loaded_table)
+ if (!loaded_table) {
+ ret = -EINVAL;
goto clean_up;
+ }
memcpy(loaded_table, rproc->cached_table, tablesz);
@@ -913,11 +914,10 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
* will be stored in the cached_table. Before the device is started,
* cached_table will be copied into devic memory.
*/
- rproc->cached_table = kmalloc(tablesz, GFP_KERNEL);
+ rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
if (!rproc->cached_table)
goto out;
- memcpy(rproc->cached_table, table, tablesz);
rproc->table_ptr = rproc->cached_table;
/* count the number of notify-ids */
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 157a57309601..9d30809bb407 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -248,6 +248,5 @@ void __init rproc_init_debugfs(void)
void __exit rproc_exit_debugfs(void)
{
- if (rproc_dbg)
- debugfs_remove(rproc_dbg);
+ debugfs_remove(rproc_dbg);
}
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 157e762c1571..70701a50ddfa 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -107,12 +107,12 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
static inline
struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
- const struct firmware *fw)
+ const struct firmware *fw)
{
if (rproc->fw_ops->find_loaded_rsc_table)
return rproc->fw_ops->find_loaded_rsc_table(rproc, fw);
- return NULL;
+ return NULL;
}
extern const struct rproc_fw_ops rproc_elf_fw_ops;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 76e4c039f0d5..d35a5d6c8d7c 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -1,10 +1,10 @@
-/*
+/*
* ASCII values for a number of symbolic constants, printing functions,
* etc.
* Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
- * Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624
+ * Updated to SPC-4 T10/1713-D Rev 36g, D. Gilbert 20130701
*/
#include <linux/blkdev.h>
@@ -21,12 +21,13 @@
/* Commands with service actions that change the command name */
-#define MAINTENANCE_IN 0xa3
-#define MAINTENANCE_OUT 0xa4
#define SERVICE_ACTION_IN_12 0xab
#define SERVICE_ACTION_OUT_12 0xa9
+#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
#define SERVICE_ACTION_IN_16 0x9e
#define SERVICE_ACTION_OUT_16 0x9f
+#define THIRD_PARTY_COPY_OUT 0x83
+#define THIRD_PARTY_COPY_IN 0x84
@@ -36,11 +37,11 @@ static const char * cdb_byte0_names[] = {
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
"Reassign Blocks",
/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
-/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
+/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
"Reserve(6)",
/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)",
-/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
+/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
/* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
/* 20-22 */ NULL, NULL, NULL,
/* 23-28 */ "Read Format Capacities", "Set Window",
@@ -48,16 +49,16 @@ static const char * cdb_byte0_names[] = {
/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
"Read updated block",
/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
-/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
- "Read Defect Data(10)",
-/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
- "Read Buffer",
+ "Read Defect Data(10)",
+/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
+ "Read Buffer",
/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
/* 40-41 */ "Change Definition", "Write Same(10)",
/* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP",
"Read density support", "Play audio(10)", "Get configuration",
- "Play audio msf", "Play audio track/index",
+ "Play audio msf", "Sanitize/Play audio track/index",
/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
@@ -72,17 +73,17 @@ static const char * cdb_byte0_names[] = {
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB",
"Variable length",
-/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
- "Receive copy results",
+/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)",
+ "Third party copy out", "Third party copy in",
/* 85-89 */ "ATA command pass through(16)", "Access control in",
- "Access control out", "Read(16)", "Memory Export Out(16)",
+ "Access control out", "Read(16)", "Compare and Write",
/* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes",
"Write and verify(16)", "Verify(16)",
/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
"Lock/unlock cache(16)", "Write same(16)", NULL,
/* 95-99 */ NULL, NULL, NULL, NULL, NULL,
-/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)",
- "Service action out(16)",
+/* 9a-9f */ NULL, NULL, NULL, "Service action bidirectional",
+ "Service action in(16)", "Service action out(16)",
/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank",
"Security protocol in", "Maintenance in", "Maintenance out",
"Move medium/play audio(12)",
@@ -122,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = {
{0x6, "Set identifying information"},
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
+ {0xc, "Remove I_T nexus"},
{0xe, "Set priority"},
{0xf, "Set timestamp"},
{0x10, "Management protocol out"},
@@ -138,10 +140,16 @@ static const struct value_name_pair serv_out12_arr[] = {
};
#define SERV_OUT12_SZ ARRAY_SIZE(serv_out12_arr)
+static const struct value_name_pair serv_bidi_arr[] = {
+ {-1, "dummy entry"},
+};
+#define SERV_BIDI_SZ ARRAY_SIZE(serv_bidi_arr)
+
static const struct value_name_pair serv_in16_arr[] = {
{0x10, "Read capacity(16)"},
{0x11, "Read long(16)"},
{0x12, "Get LBA status"},
+ {0x13, "Report referrals"},
};
#define SERV_IN16_SZ ARRAY_SIZE(serv_in16_arr)
@@ -151,6 +159,51 @@ static const struct value_name_pair serv_out16_arr[] = {
};
#define SERV_OUT16_SZ ARRAY_SIZE(serv_out16_arr)
+static const struct value_name_pair pr_in_arr[] = {
+ {0x0, "Persistent reserve in, read keys"},
+ {0x1, "Persistent reserve in, read reservation"},
+ {0x2, "Persistent reserve in, report capabilities"},
+ {0x3, "Persistent reserve in, read full status"},
+};
+#define PR_IN_SZ ARRAY_SIZE(pr_in_arr)
+
+static const struct value_name_pair pr_out_arr[] = {
+ {0x0, "Persistent reserve out, register"},
+ {0x1, "Persistent reserve out, reserve"},
+ {0x2, "Persistent reserve out, release"},
+ {0x3, "Persistent reserve out, clear"},
+ {0x4, "Persistent reserve out, preempt"},
+ {0x5, "Persistent reserve out, preempt and abort"},
+ {0x6, "Persistent reserve out, register and ignore existing key"},
+ {0x7, "Persistent reserve out, register and move"},
+};
+#define PR_OUT_SZ ARRAY_SIZE(pr_out_arr)
+
+/* SPC-4 rev 34 renamed the Extended Copy opcode to Third Party Copy Out.
+ LID1 (List Identifier length: 1 byte) is the Extended Copy found in SPC-2
+ and SPC-3 */
+static const struct value_name_pair tpc_out_arr[] = {
+ {0x0, "Extended copy(LID1)"},
+ {0x1, "Extended copy(LID4)"},
+ {0x10, "Populate token"},
+ {0x11, "Write using token"},
+ {0x1c, "Copy operation abort"},
+};
+#define TPC_OUT_SZ ARRAY_SIZE(tpc_out_arr)
+
+static const struct value_name_pair tpc_in_arr[] = {
+ {0x0, "Receive copy status(LID1)"},
+ {0x1, "Receive copy data(LID1)"},
+ {0x3, "Receive copy operating parameters"},
+ {0x4, "Receive copy failure details(LID1)"},
+ {0x5, "Receive copy status(LID4)"},
+ {0x6, "Receive copy data(LID4)"},
+ {0x7, "Receive ROD token information"},
+ {0x8, "Report all ROD tokens"},
+};
+#define TPC_IN_SZ ARRAY_SIZE(tpc_in_arr)
+
+
static const struct value_name_pair variable_length_arr[] = {
{0x1, "Rebuild(32)"},
{0x2, "Regenerate(32)"},
@@ -207,6 +260,7 @@ static const char * get_sa_name(const struct value_name_pair * arr,
static void print_opcode_name(unsigned char * cdbp, int cdb_len)
{
int sa, len, cdb0;
+ int fin_name = 0;
const char * name;
cdb0 = cdbp[0];
@@ -219,7 +273,8 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
- name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ, sa);
+ name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ,
+ sa);
if (name)
printk("%s", name);
else
@@ -232,50 +287,57 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
case MAINTENANCE_IN:
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
break;
case MAINTENANCE_OUT:
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
+ break;
+ case PERSISTENT_RESERVE_IN:
+ sa = cdbp[1] & 0x1f;
+ name = get_sa_name(pr_in_arr, PR_IN_SZ, sa);
+ fin_name = 1;
+ break;
+ case PERSISTENT_RESERVE_OUT:
+ sa = cdbp[1] & 0x1f;
+ name = get_sa_name(pr_out_arr, PR_OUT_SZ, sa);
+ fin_name = 1;
break;
case SERVICE_ACTION_IN_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
break;
case SERVICE_ACTION_OUT_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
+ break;
+ case SERVICE_ACTION_BIDIRECTIONAL:
+ sa = cdbp[1] & 0x1f;
+ name = get_sa_name(serv_bidi_arr, SERV_BIDI_SZ, sa);
+ fin_name = 1;
break;
case SERVICE_ACTION_IN_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
break;
case SERVICE_ACTION_OUT_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ fin_name = 1;
+ break;
+ case THIRD_PARTY_COPY_IN:
+ sa = cdbp[1] & 0x1f;
+ name = get_sa_name(tpc_in_arr, TPC_IN_SZ, sa);
+ fin_name = 1;
+ break;
+ case THIRD_PARTY_COPY_OUT:
+ sa = cdbp[1] & 0x1f;
+ name = get_sa_name(tpc_out_arr, TPC_OUT_SZ, sa);
+ fin_name = 1;
break;
default:
if (cdb0 < 0xc0) {
@@ -288,6 +350,12 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
printk("cdb[0]=0x%x (vendor)", cdb0);
break;
}
+ if (fin_name) {
+ if (name)
+ printk("%s", name);
+ else
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ }
}
#else /* ifndef CONFIG_SCSI_CONSTANTS */
@@ -312,10 +380,15 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
break;
case MAINTENANCE_IN:
case MAINTENANCE_OUT:
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
case SERVICE_ACTION_IN_12:
case SERVICE_ACTION_OUT_12:
+ case SERVICE_ACTION_BIDIRECTIONAL:
case SERVICE_ACTION_IN_16:
case SERVICE_ACTION_OUT_16:
+ case THIRD_PARTY_COPY_IN:
+ case THIRD_PARTY_COPY_OUT:
sa = cdbp[1] & 0x1f;
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
@@ -327,7 +400,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
break;
}
}
-#endif
+#endif
void __scsi_print_command(unsigned char *cdb)
{
@@ -336,7 +409,7 @@ void __scsi_print_command(unsigned char *cdb)
print_opcode_name(cdb, 0);
len = scsi_command_size(cdb);
/* print out all bytes in cdb */
- for (k = 0; k < len; ++k)
+ for (k = 0; k < len; ++k)
printk(" %02x", cdb[k]);
printk("\n");
}
@@ -404,8 +477,9 @@ struct error_info {
/*
* The canonical list of T10 Additional Sense Codes is available at:
- * http://www.t10.org/lists/asc-num.txt
+ * http://www.t10.org/lists/asc-num.txt [most recent: 20130605]
*/
+
static const struct error_info additional[] =
{
{0x0000, "No additional sense information"},
@@ -430,6 +504,8 @@ static const struct error_info additional[] =
{0x001C, "Verify operation in progress"},
{0x001D, "ATA pass through information available"},
{0x001E, "Conflicting SA creation request"},
+ {0x001F, "Logical unit transitioning to another power condition"},
+ {0x0020, "Extended copy information available"},
{0x0100, "No index/sector signal"},
@@ -460,6 +536,17 @@ static const struct error_info additional[] =
{0x0412, "Logical unit not ready, offline"},
{0x0413, "Logical unit not ready, SA creation in progress"},
{0x0414, "Logical unit not ready, space allocation in progress"},
+ {0x0415, "Logical unit not ready, robotics disabled"},
+ {0x0416, "Logical unit not ready, configuration required"},
+ {0x0417, "Logical unit not ready, calibration required"},
+ {0x0418, "Logical unit not ready, a door is open"},
+ {0x0419, "Logical unit not ready, operating in sequential mode"},
+ {0x041A, "Logical unit not ready, start stop unit command in "
+ "progress"},
+ {0x041B, "Logical unit not ready, sanitize in progress"},
+ {0x041C, "Logical unit not ready, additional power use not yet "
+ "granted"},
+ {0x041D, "Logical unit not ready, configuration in progress"},
{0x0500, "Logical unit does not respond to selection"},
@@ -490,6 +577,7 @@ static const struct error_info additional[] =
{0x0B06, "Warning - non-volatile cache now volatile"},
{0x0B07, "Warning - degraded power to non-volatile cache"},
{0x0B08, "Warning - power loss expected"},
+ {0x0B09, "Warning - device statistics notification active"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@@ -505,6 +593,7 @@ static const struct error_info additional[] =
{0x0C0B, "Auxiliary memory write error"},
{0x0C0C, "Write error - unexpected unsolicited data"},
{0x0C0D, "Write error - not enough unsolicited data"},
+ {0x0C0E, "Multiple write errors"},
{0x0C0F, "Defects in error window"},
{0x0D00, "Error detected by third party temporary initiator"},
@@ -523,6 +612,8 @@ static const struct error_info additional[] =
{0x1001, "Logical block guard check failed"},
{0x1002, "Logical block application tag check failed"},
{0x1003, "Logical block reference tag check failed"},
+ {0x1004, "Logical block protection error on recover buffered data"},
+ {0x1005, "Logical block protection method error"},
{0x1100, "Unrecovered read error"},
{0x1101, "Read retries exhausted"},
@@ -545,6 +636,7 @@ static const struct error_info additional[] =
{0x1112, "Auxiliary memory read error"},
{0x1113, "Read error - failed retransmission request"},
{0x1114, "Read error - lba marked bad by application client"},
+ {0x1115, "Write after sanitize required"},
{0x1200, "Address mark not found for id field"},
@@ -622,6 +714,7 @@ static const struct error_info additional[] =
{0x2009, "Access denied - invalid LU identifier"},
{0x200A, "Access denied - invalid proxy token"},
{0x200B, "Access denied - ACL LUN conflict"},
+ {0x200C, "Illegal command when not in append-only mode"},
{0x2100, "Logical block address out of range"},
{0x2101, "Invalid element address"},
@@ -630,6 +723,19 @@ static const struct error_info additional[] =
{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
+ {0x2300, "Invalid token operation, cause not reportable"},
+ {0x2301, "Invalid token operation, unsupported token type"},
+ {0x2302, "Invalid token operation, remote token usage not supported"},
+ {0x2303, "Invalid token operation, remote rod token creation not "
+ "supported"},
+ {0x2304, "Invalid token operation, token unknown"},
+ {0x2305, "Invalid token operation, token corrupt"},
+ {0x2306, "Invalid token operation, token revoked"},
+ {0x2307, "Invalid token operation, token expired"},
+ {0x2308, "Invalid token operation, token cancelled"},
+ {0x2309, "Invalid token operation, token deleted"},
+ {0x230A, "Invalid token operation, invalid token length"},
+
{0x2400, "Invalid field in cdb"},
{0x2401, "CDB decryption error"},
{0x2402, "Obsolete"},
@@ -705,6 +811,7 @@ static const struct error_info additional[] =
"event"},
{0x2A13, "Data encryption key instance counter has changed"},
{0x2A14, "SA creation capabilities data has changed"},
+ {0x2A15, "Medium removal prevention preempted"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@@ -720,6 +827,7 @@ static const struct error_info additional[] =
{0x2C09, "Previous reservation conflict status"},
{0x2C0A, "Partition or collection contains user objects"},
{0x2C0B, "Not reserved"},
+ {0x2C0C, "Orwrite generation does not match"},
{0x2D00, "Overwrite error on update in place"},
@@ -728,6 +836,7 @@ static const struct error_info additional[] =
{0x2F00, "Commands cleared by another initiator"},
{0x2F01, "Commands cleared by power loss notification"},
{0x2F02, "Commands cleared by device server"},
+ {0x2F03, "Some commands cleared by queuing layer event"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -745,10 +854,12 @@ static const struct error_info additional[] =
{0x3010, "Medium not formatted"},
{0x3011, "Incompatible volume type"},
{0x3012, "Incompatible volume qualifier"},
+ {0x3013, "Cleaning volume expired"},
{0x3100, "Medium format corrupted"},
{0x3101, "Format command failed"},
{0x3102, "Zoned formatting failed due to spare linking"},
+ {0x3103, "Sanitize command failed"},
{0x3200, "No defect spare location available"},
{0x3201, "Defect list update failure"},
@@ -809,6 +920,8 @@ static const struct error_info additional[] =
{0x3B19, "Element enabled"},
{0x3B1A, "Data transfer device removed"},
{0x3B1B, "Data transfer device inserted"},
+ {0x3B1C, "Too many logical objects on partition to support "
+ "operation"},
{0x3D00, "Invalid bits in identify message"},
@@ -839,6 +952,7 @@ static const struct error_info additional[] =
{0x3F12, "iSCSI IP address added"},
{0x3F13, "iSCSI IP address removed"},
{0x3F14, "iSCSI IP address changed"},
+ {0x3F15, "Inspect referrals sense descriptors"},
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
@@ -848,6 +962,7 @@ static const struct error_info additional[] =
{0x4300, "Message error"},
{0x4400, "Internal target failure"},
+ {0x4401, "Persistent reservation information lost"},
{0x4471, "ATA device failed set features"},
{0x4500, "Select or reselect failure"},
@@ -876,6 +991,21 @@ static const struct error_info additional[] =
{0x4B04, "Nak received"},
{0x4B05, "Data offset error"},
{0x4B06, "Initiator response timeout"},
+ {0x4B07, "Connection lost"},
+ {0x4B08, "Data-in buffer overflow - data buffer size"},
+ {0x4B09, "Data-in buffer overflow - data buffer descriptor area"},
+ {0x4B0A, "Data-in buffer error"},
+ {0x4B0B, "Data-out buffer overflow - data buffer size"},
+ {0x4B0C, "Data-out buffer overflow - data buffer descriptor area"},
+ {0x4B0D, "Data-out buffer error"},
+ {0x4B0E, "PCIe fabric error"},
+ {0x4B0F, "PCIe completion timeout"},
+ {0x4B10, "PCIe completer abort"},
+ {0x4B11, "PCIe poisoned tlp received"},
+ {0x4B12, "PCIe eCRC check failed"},
+ {0x4B13, "PCIe unsupported request"},
+ {0x4B14, "PCIe acs violation"},
+ {0x4B15, "PCIe tlp prefix blocked"},
{0x4C00, "Logical unit failed self-configuration"},
/*
@@ -897,6 +1027,10 @@ static const struct error_info additional[] =
{0x5302, "Medium removal prevented"},
{0x5303, "Medium removal prevented by data transfer element"},
{0x5304, "Medium thread or unthread failure"},
+ {0x5305, "Volume identifier invalid"},
+ {0x5306, "Volume identifier missing"},
+ {0x5307, "Duplicate volume identifier"},
+ {0x5308, "Element status unknown"},
{0x5400, "Scsi to host system interface failure"},
@@ -911,6 +1045,9 @@ static const struct error_info additional[] =
{0x5508, "Maximum number of supplemental decryption keys exceeded"},
{0x5509, "Medium auxiliary memory not accessible"},
{0x550A, "Data currently unavailable"},
+ {0x550B, "Insufficient power for operation"},
+ {0x550C, "Insufficient resources to create rod"},
+ {0x550D, "Insufficient resources to create rod token"},
{0x5700, "Unable to recover table-of-contents"},
@@ -1069,6 +1206,7 @@ static const struct error_info additional[] =
{0x670B, "ATA device feature not enabled"},
{0x6800, "Logical unit not configured"},
+ {0x6801, "Subsidiary logical unit not configured"},
{0x6900, "Data loss on logical unit"},
{0x6901, "Multiple logical unit failures"},
@@ -1185,10 +1323,13 @@ static const char * const snstext[] = {
"Vendor Specific(9)",
"Copy Aborted", /* A: COPY or COMPARE was aborted */
"Aborted Command", /* B: The target aborted the command */
- "Equal", /* C: A SEARCH DATA command found data equal */
+ "Equal", /* C: A SEARCH DATA command found data equal,
+ reserved in SPC-4 rev 36 */
"Volume Overflow", /* D: Medium full with still data to be written */
"Miscompare", /* E: Source data and data on the medium
do not agree */
+ "Completed", /* F: command completed sense data reported,
+ may occur for successful command */
};
#endif
@@ -1306,7 +1447,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
struct scsi_sense_hdr *sshdr)
{
int k, num, res;
-
+
res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
if (0 == res) {
/* this may be SCSI-1 sense data */
@@ -1459,5 +1600,3 @@ void scsi_print_result(struct scsi_cmnd *cmd)
scsi_show_result(cmd->result);
}
EXPORT_SYMBOL(scsi_print_result);
-
-
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 4a05d0427a9c..07453bbf05e7 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -774,7 +774,6 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
struct fcoe_port *port;
struct net_device *realdev;
int rc;
- struct netdev_fcoe_hbainfo fdmi;
port = lport_priv(lport);
fcoe = port->priv;
@@ -788,9 +787,13 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
return;
if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) {
- memset(&fdmi, 0, sizeof(fdmi));
+ struct netdev_fcoe_hbainfo *fdmi;
+ fdmi = kzalloc(sizeof(*fdmi), GFP_KERNEL);
+ if (!fdmi)
+ return;
+
rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev,
- &fdmi);
+ fdmi);
if (rc) {
printk(KERN_INFO "fcoe: Failed to retrieve FDMI "
"information from netdev.\n");
@@ -800,38 +803,39 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
snprintf(fc_host_serial_number(lport->host),
FC_SERIAL_NUMBER_SIZE,
"%s",
- fdmi.serial_number);
+ fdmi->serial_number);
snprintf(fc_host_manufacturer(lport->host),
FC_SERIAL_NUMBER_SIZE,
"%s",
- fdmi.manufacturer);
+ fdmi->manufacturer);
snprintf(fc_host_model(lport->host),
FC_SYMBOLIC_NAME_SIZE,
"%s",
- fdmi.model);
+ fdmi->model);
snprintf(fc_host_model_description(lport->host),
FC_SYMBOLIC_NAME_SIZE,
"%s",
- fdmi.model_description);
+ fdmi->model_description);
snprintf(fc_host_hardware_version(lport->host),
FC_VERSION_STRING_SIZE,
"%s",
- fdmi.hardware_version);
+ fdmi->hardware_version);
snprintf(fc_host_driver_version(lport->host),
FC_VERSION_STRING_SIZE,
"%s",
- fdmi.driver_version);
+ fdmi->driver_version);
snprintf(fc_host_optionrom_version(lport->host),
FC_VERSION_STRING_SIZE,
"%s",
- fdmi.optionrom_version);
+ fdmi->optionrom_version);
snprintf(fc_host_firmware_version(lport->host),
FC_VERSION_STRING_SIZE,
"%s",
- fdmi.firmware_version);
+ fdmi->firmware_version);
/* Enable FDMI lport states */
lport->fdmi_enabled = 1;
+ kfree(fdmi);
} else {
lport->fdmi_enabled = 0;
printk(KERN_INFO "fcoe: No FDMI support.\n");
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 795843dde8ec..203415e02518 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2090,7 +2090,11 @@ static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
*/
static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
{
+ struct fc_rport_priv *rdata;
+
mutex_lock(&lport->disc.disc_mutex);
+ list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
+ lport->tt.rport_logoff(rdata);
lport->disc.disc_callback = NULL;
mutex_unlock(&lport->disc.disc_mutex);
}
diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c
index 8c05ae017f5b..c9382d6eee78 100644
--- a/drivers/scsi/fcoe/fcoe_sysfs.c
+++ b/drivers/scsi/fcoe/fcoe_sysfs.c
@@ -507,7 +507,7 @@ static const struct attribute_group *fcoe_fcf_attr_groups[] = {
NULL,
};
-struct bus_type fcoe_bus_type;
+static struct bus_type fcoe_bus_type;
static int fcoe_bus_match(struct device *dev,
struct device_driver *drv)
@@ -541,25 +541,25 @@ static void fcoe_fcf_device_release(struct device *dev)
kfree(fcf);
}
-struct device_type fcoe_ctlr_device_type = {
+static struct device_type fcoe_ctlr_device_type = {
.name = "fcoe_ctlr",
.groups = fcoe_ctlr_attr_groups,
.release = fcoe_ctlr_device_release,
};
-struct device_type fcoe_fcf_device_type = {
+static struct device_type fcoe_fcf_device_type = {
.name = "fcoe_fcf",
.groups = fcoe_fcf_attr_groups,
.release = fcoe_fcf_device_release,
};
-struct bus_attribute fcoe_bus_attr_group[] = {
+static struct bus_attribute fcoe_bus_attr_group[] = {
__ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
__ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
__ATTR_NULL
};
-struct bus_type fcoe_bus_type = {
+static struct bus_type fcoe_bus_type = {
.name = "fcoe",
.match = &fcoe_bus_match,
.bus_attrs = fcoe_bus_attr_group,
@@ -569,7 +569,7 @@ struct bus_type fcoe_bus_type = {
* fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue
* @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed
*/
-void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
+static void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
{
if (!fcoe_ctlr_work_q(ctlr)) {
printk(KERN_ERR
@@ -590,8 +590,8 @@ void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
* Return value:
* 1 on success / 0 already queued / < 0 for error
*/
-int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
- struct work_struct *work)
+static int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
+ struct work_struct *work)
{
if (unlikely(!fcoe_ctlr_work_q(ctlr))) {
printk(KERN_ERR
@@ -609,7 +609,7 @@ int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
* fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue
* @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed
*/
-void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
+static void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
{
if (!fcoe_ctlr_devloss_work_q(ctlr)) {
printk(KERN_ERR
@@ -631,9 +631,9 @@ void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
* Return value:
* 1 on success / 0 already queued / < 0 for error
*/
-int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
- struct delayed_work *work,
- unsigned long delay)
+static int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
+ struct delayed_work *work,
+ unsigned long delay)
{
if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {
printk(KERN_ERR
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 01adbe0ec53b..74277c20f6a5 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -180,24 +180,10 @@ void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
{
struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
struct net_device *netdev = fcoe_get_netdev(fip->lp);
- struct fcoe_fc_els_lesb *fcoe_lesb;
- struct fc_els_lesb fc_lesb;
-
- __fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
- fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
-
- ctlr_dev->lesb.lesb_link_fail =
- ntohl(fcoe_lesb->lesb_link_fail);
- ctlr_dev->lesb.lesb_vlink_fail =
- ntohl(fcoe_lesb->lesb_vlink_fail);
- ctlr_dev->lesb.lesb_miss_fka =
- ntohl(fcoe_lesb->lesb_miss_fka);
- ctlr_dev->lesb.lesb_symb_err =
- ntohl(fcoe_lesb->lesb_symb_err);
- ctlr_dev->lesb.lesb_err_block =
- ntohl(fcoe_lesb->lesb_err_block);
- ctlr_dev->lesb.lesb_fcs_error =
- ntohl(fcoe_lesb->lesb_fcs_error);
+ struct fc_els_lesb *fc_lesb;
+
+ fc_lesb = (struct fc_els_lesb *)(&ctlr_dev->lesb);
+ __fcoe_get_lesb(fip->lp, fc_lesb, netdev);
}
EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb);
@@ -721,7 +707,6 @@ ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
{
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
- struct fcoe_ctlr_device *ctlr_dev = NULL;
int rc = 0;
int err;
@@ -768,9 +753,8 @@ ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
goto out_putdev;
}
- LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
- ft->name, (ctlr_dev) ? "succeeded" : "failed",
- netdev->name);
+ LIBFCOE_TRANSPORT_DBG("transport %s succeeded to create fcoe on %s.\n",
+ ft->name, netdev->name);
out_putdev:
dev_put(netdev);
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 8b928c67e4b9..587992952b3c 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -337,7 +337,7 @@ static void fc_exch_release(struct fc_exch *ep)
* fc_exch_timer_cancel() - cancel exch timer
* @ep: The exchange whose timer to be canceled
*/
-static inline void fc_exch_timer_cancel(struct fc_exch *ep)
+static inline void fc_exch_timer_cancel(struct fc_exch *ep)
{
if (cancel_delayed_work(&ep->timeout_work)) {
FC_EXCH_DBG(ep, "Exchange timer canceled\n");
@@ -1567,7 +1567,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
fc_exch_rctl_name(fh->fh_r_ctl));
if (cancel_delayed_work_sync(&ep->timeout_work)) {
- FC_EXCH_DBG(ep, "Exchange timer canceled\n");
+ FC_EXCH_DBG(ep, "Exchange timer canceled due to ABTS response\n");
fc_exch_release(ep); /* release from pending timer hold */
}
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 6bbb9447b75d..c710d908fda6 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -926,6 +926,20 @@ err:
kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
}
+static bool
+fc_rport_compatible_roles(struct fc_lport *lport, struct fc_rport_priv *rdata)
+{
+ if (rdata->ids.roles == FC_PORT_ROLE_UNKNOWN)
+ return true;
+ if ((rdata->ids.roles & FC_PORT_ROLE_FCP_TARGET) &&
+ (lport->service_params & FCP_SPPF_INIT_FCN))
+ return true;
+ if ((rdata->ids.roles & FC_PORT_ROLE_FCP_INITIATOR) &&
+ (lport->service_params & FCP_SPPF_TARG_FCN))
+ return true;
+ return false;
+}
+
/**
* fc_rport_enter_plogi() - Send Port Login (PLOGI) request
* @rdata: The remote port to send a PLOGI to
@@ -938,6 +952,12 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
struct fc_lport *lport = rdata->local_port;
struct fc_frame *fp;
+ if (!fc_rport_compatible_roles(lport, rdata)) {
+ FC_RPORT_DBG(rdata, "PLOGI suppressed for incompatible role\n");
+ fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+ return;
+ }
+
FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
fc_rport_state(rdata));
@@ -1646,6 +1666,13 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
rjt_data.explan = ELS_EXPL_NONE;
goto reject;
}
+ if (!fc_rport_compatible_roles(lport, rdata)) {
+ FC_RPORT_DBG(rdata, "Received PLOGI for incompatible role\n");
+ mutex_unlock(&rdata->rp_mutex);
+ rjt_data.reason = ELS_RJT_LOGIC;
+ rjt_data.explan = ELS_EXPL_NONE;
+ goto reject;
+ }
/*
* Get session payload size from incoming PLOGI.
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 6002d363c637..0177295599e0 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -4958,10 +4958,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
sense, sense_handle);
}
- for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
- dma_free_coherent(&instance->pdev->dev,
- kern_sge32[i].length,
- kbuff_arr[i], kern_sge32[i].phys_addr);
+ for (i = 0; i < ioc->sge_count; i++) {
+ if (kbuff_arr[i])
+ dma_free_coherent(&instance->pdev->dev,
+ kern_sge32[i].length,
+ kbuff_arr[i],
+ kern_sge32[i].phys_addr);
}
megasas_return_cmd(instance, cmd);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 8056eacba758..4f401f753f8e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -585,7 +585,7 @@ u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe,
case 1:
/* start with logical arm */
arm = get_arm_from_strip(instance, ld, stripe, map);
- if (arm != -1UL)
+ if (arm != -1U)
arm *= 2;
break;
}
@@ -637,7 +637,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
if (raid->level == 6) {
logArm = get_arm_from_strip(instance, ld, stripRow, map);
- if (logArm == -1UL)
+ if (logArm == -1U)
return FALSE;
rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig
index 81471bf415d8..d53e1b02e893 100644
--- a/drivers/scsi/mpt3sas/Kconfig
+++ b/drivers/scsi/mpt3sas/Kconfig
@@ -2,7 +2,7 @@
# Kernel configuration file for the MPT3SAS
#
# This code is based on drivers/scsi/mpt3sas/Kconfig
-# Copyright (C) 2012 LSI Corporation
+# Copyright (C) 2012-2013 LSI Corporation
# (mailto:DL-MPTFusionLinux@lsi.com)
# This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h
index 03317ffea62c..20da8f907c00 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.26
+ * mpi2.h Version: 02.00.29
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -82,6 +82,10 @@
* 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT.
* Added Hard Reset delay timings.
* 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
* --------------------------------------------------------------------------
*/
@@ -115,7 +119,7 @@
#define MPI2_VERSION_02_05 (0x0205)
/*Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x1A)
+#define MPI2_HEADER_VERSION_UNIT (0x1D)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -274,6 +278,8 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF)
#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000)
#define MPI2_RPHI_MSIX_INDEX_SHIFT (24)
+#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /*MPI v2.5 only*/
+
/*
*Defines for the HCBSize and address
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
index d8b2c3eedb57..889aa7067899 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2011 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_cnfg.h
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.22
+ * mpi2_cnfg.h Version: 02.00.24
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -155,6 +155,11 @@
* Added UEFIVersion field to BIOS Page 1 and defined new
* BiosOptions bits.
* Incorporating additions for MPI v2.5.
+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
+ * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
+ * obsolete for MPI v2.5 and later.
+ * Added some defines for 12G SAS speeds.
* --------------------------------------------------------------------------
*/
@@ -714,6 +719,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 {
#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
/*defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
@@ -1310,6 +1316,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
/*values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
+
#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
@@ -1884,6 +1893,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 {
#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80)
#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90)
#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0)
+#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0)
#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F)
#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00)
#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08)
@@ -1897,6 +1907,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 {
#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80)
#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90)
#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0)
+#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0)
#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F)
#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08)
#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_init.h b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
index a079e5242474..f7928bf66478 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_init.h
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
index 0de425d8fd70..e2bb82143720 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.21
+ * mpi2_ioc.h Version: 02.00.22
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -124,6 +124,9 @@
* Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
* 11-18-11 02.00.20 Incorporating additions for MPI v2.5.
* 03-29-12 02.00.21 Added a product specific range to event values.
+ * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
+ * Added ElapsedSeconds field to
+ * MPI2_EVENT_DATA_IR_OPERATION_STATUS.
* --------------------------------------------------------------------------
*/
@@ -283,6 +286,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0)
/*IOCExceptions */
+#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200)
#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100)
#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0)
@@ -634,7 +638,7 @@ typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS {
U8 RAIDOperation; /*0x04 */
U8 PercentComplete; /*0x05 */
U16 Reserved2; /*0x06 */
- U32 Resereved3; /*0x08 */
+ U32 ElapsedSeconds; /*0x08 */
} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
*PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
Mpi2EventDataIrOperationStatus_t,
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
index d1d9866cf300..71765236afef 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.08
+ * mpi2_raid.h Version: 02.00.09
*
* Version History
* ---------------
@@ -28,6 +28,8 @@
* Added product-specific range to RAID Action values.
* 11-18-11 02.00.07 Incorporating additions for MPI v2.5.
* 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
+ * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
+ * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
* --------------------------------------------------------------------------
*/
@@ -269,10 +271,12 @@ typedef struct _MPI2_RAID_VOL_INDICATOR {
U64 TotalBlocks; /*0x00 */
U64 BlocksRemaining; /*0x08 */
U32 Flags; /*0x10 */
+ U32 ElapsedSeconds; /* 0x14 */
} MPI2_RAID_VOL_INDICATOR, *PTR_MPI2_RAID_VOL_INDICATOR,
Mpi2RaidVolIndicator_t, *pMpi2RaidVolIndicator_t;
/*defines for RAID Volume Indicator Flags field */
+#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000)
#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F)
#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000)
#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
@@ -312,7 +316,7 @@ typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT {
/*RAID Action Reply ActionData union */
typedef union _MPI2_RAID_ACTION_REPLY_DATA {
- U32 Word[5];
+ U32 Word[6];
MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
U16 VolDevHandle;
U8 VolumeState;
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
index b4e7084aba31..cba046f6a4b4 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_sas.h
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
index 71453d11c1c1..34e9a7ba76b0 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.09
+ * mpi2_tool.h Version: 02.00.10
*
* Version History
* ---------------
@@ -30,6 +30,8 @@
* 11-18-11 02.00.08 Incorporating additions for MPI v2.5.
* 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request
* message.
+ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
+ * it uses MPI Chain SGE as well as MPI Simple SGE.
* --------------------------------------------------------------------------
*/
@@ -279,7 +281,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
U16 Reserved6; /*0x0E */
U32 DataLength; /*0x10 */
U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */
- MPI2_SGE_SIMPLE_UNION SGL; /*0x70 */
+ MPI2_MPI_SGE_IO_UNION SGL; /*0x70 */
} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
*PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
Mpi2ToolboxDiagnosticCliRequest_t,
@@ -302,7 +304,7 @@ typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
U32 Reserved5; /*0x0C */
U32 DataLength; /*0x10 */
U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */
- MPI25_SGE_IO_UNION SGL; /*0x70 */
+ MPI25_SGE_IO_UNION SGL; /* 0x70 */
} MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
*PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
Mpi25ToolboxDiagnosticCliRequest_t,
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_type.h b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
index 516f959573f5..ba1fed50966e 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_type.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_type.h
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 18360032a520..5dc280c75325 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -4090,11 +4090,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
&ioc->chip->HostDiagnostic);
- /* don't access any registers for 50 milliseconds */
- msleep(50);
+ /*This delay allows the chip PCIe hardware time to finish reset tasks*/
+ if (sleep_flag == CAN_SLEEP)
+ msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
+ else
+ mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
- /* 300 second max wait */
- for (count = 0; count < 3000000 ; count++) {
+ /* Approximately 300 second max wait */
+ for (count = 0; count < (300000000 /
+ MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
host_diagnostic = readl(&ioc->chip->HostDiagnostic);
@@ -4103,11 +4107,13 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
break;
- /* wait 1 msec */
+ /* Wait to pass the second read delay window */
if (sleep_flag == CAN_SLEEP)
- usleep_range(1000, 1500);
+ msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
+ / 1000);
else
- mdelay(1);
+ mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
+ / 1000);
}
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 994656cbfac9..0ebf5d913c80 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -70,10 +70,10 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "01.100.01.00"
-#define MPT3SAS_MAJOR_VERSION 1
+#define MPT3SAS_DRIVER_VERSION "02.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 2
#define MPT3SAS_MINOR_VERSION 100
-#define MPT3SAS_BUILD_VERSION 1
+#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
/*
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 4db0c7a18bd8..936ec0391990 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -2,7 +2,7 @@
* This module provides common API for accessing firmware configuration pages
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 0b402b6f2d26..9b89de14a0a3 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
index bd89f4f00550..53b0c480d98f 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h
index 35405e7044f8..545b22d2cbdf 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_debug.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h
@@ -2,7 +2,7 @@
* Logging Support for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index dcbf7c880cb2..8cbe8fd21fc4 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -2,7 +2,7 @@
* Scsi Host Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -675,11 +675,12 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
* devices while scanning is turned on due to an oops in
* scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
*/
- if (!ioc->is_driver_loading)
+ if (!ioc->is_driver_loading) {
mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ }
}
}
@@ -1273,6 +1274,7 @@ _scsih_slave_alloc(struct scsi_device *sdev)
struct MPT3SAS_DEVICE *sas_device_priv_data;
struct scsi_target *starget;
struct _raid_device *raid_device;
+ struct _sas_device *sas_device;
unsigned long flags;
sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
@@ -1301,6 +1303,19 @@ _scsih_slave_alloc(struct scsi_device *sdev)
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
+ if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_target_priv_data->sas_address);
+ if (sas_device && (sas_device->starget == NULL)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s : sas_device->starget set to starget @ %d\n",
+ __func__, __LINE__);
+ sas_device->starget = starget;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ }
+
return 0;
}
@@ -6392,7 +6407,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
handle))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
break;
handle = le16_to_cpu(sas_device_pg0.DevHandle);
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
@@ -6494,7 +6509,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
&volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
break;
handle = le16_to_cpu(volume_pg1.DevHandle);
@@ -6518,7 +6533,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
phys_disk_num))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
break;
phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle);
@@ -6597,7 +6612,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
break;
handle = le16_to_cpu(expander_pg0.DevHandle);
@@ -6742,8 +6757,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6787,8 +6800,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
phys_disk_num))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6854,8 +6865,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
&volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6914,8 +6923,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
handle))) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\
" ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7525,10 +7532,12 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
- if (!ioc->is_driver_loading)
- mpt3sas_transport_port_remove(ioc, sas_address,
+ if (!ioc->is_driver_loading) {
+ mpt3sas_transport_port_remove(ioc,
+ sas_address,
sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ }
}
}
}
@@ -7584,13 +7593,14 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
* oops in scsi_sysfs_add_sdev()->add_device()->
* sysfs_addrm_start()
*/
- if (!ioc->is_driver_loading)
+ if (!ioc->is_driver_loading) {
mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
- list_del(&sas_device->list);
- kfree(sas_device);
- continue;
+ list_del(&sas_device->list);
+ kfree(sas_device);
+ continue;
+ }
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 87ca2b7287c3..dcadd56860ff 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -2,7 +2,7 @@
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
index 6f8d6213040b..f6533ab20364 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
@@ -3,7 +3,7 @@
* (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
index a10c30907394..bb693923bef1 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
@@ -4,7 +4,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
- * Copyright (C) 2012 LSI Corporation
+ * Copyright (C) 2012-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index e4b9bc7f5410..3861aa1f4520 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -912,14 +912,13 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
struct pm8001_hba_info *pm8001_ha;
- int i , pos;
+ int i;
u32 device_state;
pm8001_ha = sha->lldd_ha;
flush_workqueue(pm8001_wq);
scsi_block_requests(pm8001_ha->shost);
- pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pos == 0) {
- printk(KERN_ERR " PCI PM not supported\n");
+ if (!pdev->pm_cap) {
+ dev_err(&pdev->dev, " PCI PM not supported\n");
return -ENODEV;
}
PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index bf60c631abb5..d7a99ae7f39d 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1691,6 +1691,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
if (unlikely(pci_channel_offline(ha->pdev)))
goto done;
+ if (qla2x00_reset_active(vha))
+ goto done;
+
stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
if (stats == NULL) {
ql_log(ql_log_warn, vha, 0x707d,
@@ -1703,7 +1706,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
if (IS_FWI2_CAPABLE(ha)) {
rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
} else if (atomic_read(&base_vha->loop_state) == LOOP_READY &&
- !qla2x00_reset_active(vha) && !ha->dpc_active) {
+ !ha->dpc_active) {
/* Must be in a 'READY' state for statistics retrieval. */
rval = qla2x00_get_link_status(base_vha, base_vha->loop_id,
stats, stats_dma);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 39719f892488..417eaad50ae2 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -269,6 +269,12 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
type = "FC_BSG_HST_ELS_NOLOGIN";
}
+ if (!vha->flags.online) {
+ ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
+ rval = -EIO;
+ goto done;
+ }
+
/* pass through is supported only for ISP 4Gb or higher */
if (!IS_FWI2_CAPABLE(ha)) {
ql_dbg(ql_dbg_user, vha, 0x7001,
@@ -326,12 +332,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
NPH_FABRIC_CONTROLLER : NPH_F_PORT;
}
- if (!vha->flags.online) {
- ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
- rval = -EIO;
- goto done;
- }
-
req_sg_cnt =
dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -399,7 +399,7 @@ done_unmap_sg:
goto done_free_fcport;
done_free_fcport:
- if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
+ if (bsg_job->request->msgcode == FC_BSG_RPT_ELS)
kfree(fcport);
done:
return rval;
@@ -1084,14 +1084,6 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
return -EINVAL;
}
- ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request +
- sizeof(struct fc_bsg_request));
- if (!ql84_mgmt) {
- ql_log(ql_log_warn, vha, 0x703b,
- "MGMT header not provided, exiting.\n");
- return -EINVAL;
- }
-
mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
if (!mn) {
ql_log(ql_log_warn, vha, 0x703c,
@@ -1102,7 +1094,7 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
memset(mn, 0, sizeof(struct access_chip_84xx));
mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
mn->entry_count = 1;
-
+ ql84_mgmt = (void *)bsg_job->request + sizeof(struct fc_bsg_request);
switch (ql84_mgmt->mgmt.cmd) {
case QLA84_MGMT_READ_MEM:
case QLA84_MGMT_GET_INFO:
@@ -1282,14 +1274,7 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
return -EINVAL;
}
- port_param = (struct qla_port_param *)((char *)bsg_job->request +
- sizeof(struct fc_bsg_request));
- if (!port_param) {
- ql_log(ql_log_warn, vha, 0x7047,
- "port_param header not provided.\n");
- return -EINVAL;
- }
-
+ port_param = (void *)bsg_job->request + sizeof(struct fc_bsg_request);
if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
ql_log(ql_log_warn, vha, 0x7048,
"Invalid destination type.\n");
@@ -2153,6 +2138,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
(sp->type == SRB_ELS_CMD_HST) ||
(sp->type == SRB_FXIOCB_BCMD))
&& (sp->u.bsg_job == bsg_job)) {
+ req->outstanding_cmds[cnt] = NULL;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
ql_log(ql_log_warn, vha, 0x7089,
@@ -2180,8 +2166,6 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
done:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (bsg_job->request->msgcode == FC_BSG_HST_CT)
- kfree(sp->fcport);
- qla2x00_rel_sp(vha, sp);
+ sp->free(vha, sp);
return 0;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index cfa2a20dee97..df132fec6d86 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -12,9 +12,10 @@
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
* | Module Init and Probe | 0x014f | 0x4b,0xba,0xfa |
- * | Mailbox commands | 0x1179 | 0x111a-0x111b |
+ * | Mailbox commands | 0x117a | 0x111a-0x111b |
* | | | 0x1155-0x1158 |
* | Device Discovery | 0x2095 | 0x2020-0x2022, |
+ * | | | 0x2011-0x2012, |
* | | | 0x2016 |
* | Queue Command and IO tracing | 0x3058 | 0x3006-0x300b |
* | | | 0x3027-0x3028 |
@@ -35,7 +36,8 @@
* | | | 0x70a5,0x70a6, |
* | | | 0x70a8,0x70ab, |
* | | | 0x70ad-0x70ae, |
- * | | | 0x70d1-0x70da |
+ * | | | 0x70d1-0x70da, |
+ * | | | 0x7047,0x703b |
* | Task Management | 0x803c | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
@@ -1468,7 +1470,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
nxt = qla2xxx_copy_queues(ha, nxt);
- nxt = qla24xx_copy_eft(ha, nxt);
+ qla24xx_copy_eft(ha, nxt);
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
@@ -1787,7 +1789,7 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
nxt = qla2xxx_copy_queues(ha, nxt);
- nxt = qla24xx_copy_eft(ha, nxt);
+ qla24xx_copy_eft(ha, nxt);
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
@@ -2289,7 +2291,7 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
copy_queue:
nxt = qla2xxx_copy_queues(ha, nxt);
- nxt = qla24xx_copy_eft(ha, nxt);
+ qla24xx_copy_eft(ha, nxt);
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c32efc753229..95ca32a71e75 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -323,7 +323,7 @@ struct srb_iocb {
uint32_t lun;
uint32_t data;
struct completion comp;
- uint32_t comp_status;
+ __le16 comp_status;
} tmf;
struct {
#define SRB_FXDISC_REQ_DMA_VALID BIT_0
@@ -338,21 +338,21 @@ struct srb_iocb {
void *rsp_addr;
dma_addr_t req_dma_handle;
dma_addr_t rsp_dma_handle;
- uint32_t adapter_id;
- uint32_t adapter_id_hi;
- uint32_t req_func_type;
- uint32_t req_data;
- uint32_t req_data_extra;
- uint32_t result;
- uint32_t seq_number;
- uint32_t fw_flags;
+ __le32 adapter_id;
+ __le32 adapter_id_hi;
+ __le16 req_func_type;
+ __le32 req_data;
+ __le32 req_data_extra;
+ __le32 result;
+ __le32 seq_number;
+ __le16 fw_flags;
struct completion fxiocb_comp;
- uint32_t reserved_0;
+ __le32 reserved_0;
uint8_t reserved_1;
} fxiocb;
struct {
uint32_t cmd_hndl;
- uint32_t comp_status;
+ __le16 comp_status;
struct completion comp;
} abt;
} u;
@@ -1196,14 +1196,14 @@ typedef struct {
struct init_cb_fx {
uint16_t version;
uint16_t reserved_1[13];
- uint16_t request_q_outpointer;
- uint16_t response_q_inpointer;
+ __le16 request_q_outpointer;
+ __le16 response_q_inpointer;
uint16_t reserved_2[2];
- uint16_t response_q_length;
- uint16_t request_q_length;
+ __le16 response_q_length;
+ __le16 request_q_length;
uint16_t reserved_3[2];
- uint32_t request_q_address[2];
- uint32_t response_q_address[2];
+ __le32 request_q_address[2];
+ __le32 response_q_address[2];
uint16_t reserved_4[4];
uint8_t response_q_msivec;
uint8_t reserved_5[19];
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 026bfde33e67..2d98232a08eb 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -587,7 +587,7 @@ extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
extern int qlafx00_fw_ready(scsi_qla_host_t *);
extern int qlafx00_configure_devices(scsi_qla_host_t *);
extern int qlafx00_reset_initialize(scsi_qla_host_t *);
-extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint8_t);
+extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint16_t);
extern int qlafx00_process_aen(struct scsi_qla_host *, struct qla_work_evt *);
extern int qlafx00_post_aenfx_work(struct scsi_qla_host *, uint32_t,
uint32_t *, int);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index d0ea8b921177..0926451980ed 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -99,17 +99,17 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
* Returns a pointer to the intitialized @ct_req.
*/
static inline struct ct_sns_req *
-qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size)
+qla2x00_prep_ct_req(struct ct_sns_pkt *p, uint16_t cmd, uint16_t rsp_size)
{
- memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+ memset(p, 0, sizeof(struct ct_sns_pkt));
- ct_req->header.revision = 0x01;
- ct_req->header.gs_type = 0xFC;
- ct_req->header.gs_subtype = 0x02;
- ct_req->command = cpu_to_be16(cmd);
- ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+ p->p.req.header.revision = 0x01;
+ p->p.req.header.gs_type = 0xFC;
+ p->p.req.header.gs_subtype = 0x02;
+ p->p.req.command = cpu_to_be16(cmd);
+ p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
- return (ct_req);
+ return &p->p.req;
}
static int
@@ -188,7 +188,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
GA_NXT_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GA_NXT_CMD,
GA_NXT_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -284,8 +284,7 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
gid_pt_rsp_size);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
- gid_pt_rsp_size);
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GID_PT_CMD, gid_pt_rsp_size);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare CT arguments -- port_type */
@@ -359,7 +358,7 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
GPN_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GPN_ID_CMD,
GPN_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -421,7 +420,7 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
GNN_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GNN_ID_CMD,
GNN_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -495,7 +494,7 @@ qla2x00_rft_id(scsi_qla_host_t *vha)
RFT_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, RFT_ID_CMD,
RFT_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -551,7 +550,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
RFF_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, RFF_ID_CMD,
RFF_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -606,8 +605,7 @@ qla2x00_rnn_id(scsi_qla_host_t *vha)
RNN_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
- RNN_ID_RSP_SIZE);
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, RNN_ID_CMD, RNN_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare CT arguments -- port_id, node_name */
@@ -676,7 +674,7 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
ms_pkt = ha->isp_ops->prep_ms_iocb(vha, 0, RSNN_NN_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, RSNN_NN_CMD,
RSNN_NN_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -1262,18 +1260,18 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
* Returns a pointer to the intitialized @ct_req.
*/
static inline struct ct_sns_req *
-qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd,
+qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd,
uint16_t rsp_size)
{
- memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+ memset(p, 0, sizeof(struct ct_sns_pkt));
- ct_req->header.revision = 0x01;
- ct_req->header.gs_type = 0xFA;
- ct_req->header.gs_subtype = 0x10;
- ct_req->command = cpu_to_be16(cmd);
- ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+ p->p.req.header.revision = 0x01;
+ p->p.req.header.gs_type = 0xFA;
+ p->p.req.header.gs_subtype = 0x10;
+ p->p.req.command = cpu_to_be16(cmd);
+ p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
- return ct_req;
+ return &p->p.req;
}
/**
@@ -1301,8 +1299,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
- RHBA_RSP_SIZE);
+ ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, RHBA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- attribute block, attributes. */
@@ -1370,8 +1367,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
/* Model description. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION);
- if (ha->model_desc)
- strncpy(eiter->a.model_desc, ha->model_desc, 80);
+ strncpy(eiter->a.model_desc, ha->model_desc, 80);
alen = strlen(eiter->a.model_desc);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
@@ -1491,8 +1487,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
DHBA_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD,
- DHBA_RSP_SIZE);
+ ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, DHBA_CMD, DHBA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- portname. */
@@ -1548,8 +1543,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
- RPA_RSP_SIZE);
+ ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, RPA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- attribute block, attributes. */
@@ -1776,7 +1770,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
GFPN_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFPN_ID_CMD,
GFPN_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
@@ -1843,18 +1837,18 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *vha, uint32_t req_size,
static inline struct ct_sns_req *
-qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
+qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd,
uint16_t rsp_size)
{
- memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+ memset(p, 0, sizeof(struct ct_sns_pkt));
- ct_req->header.revision = 0x01;
- ct_req->header.gs_type = 0xFA;
- ct_req->header.gs_subtype = 0x01;
- ct_req->command = cpu_to_be16(cmd);
- ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+ p->p.req.header.revision = 0x01;
+ p->p.req.header.gs_type = 0xFA;
+ p->p.req.header.gs_subtype = 0x01;
+ p->p.req.command = cpu_to_be16(cmd);
+ p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
- return ct_req;
+ return &p->p.req;
}
/**
@@ -1890,8 +1884,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
GPSC_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
- GPSC_CMD, GPSC_RSP_SIZE);
+ ct_req = qla24xx_prep_ct_fm_req(ha->ct_sns, GPSC_CMD,
+ GPSC_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare CT arguments -- port_name */
@@ -2001,7 +1995,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
GFF_ID_RSP_SIZE);
/* Prepare CT request */
- ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD,
+ ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFF_ID_CMD,
GFF_ID_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 3565dfd8f370..f2216ed2ad8c 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2309,14 +2309,6 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
"Topology - %s, Host Loop address 0x%x.\n",
connect_type, vha->loop_id);
- if (rval) {
- ql_log(ql_log_warn, vha, 0x2011,
- "%s FAILED\n", __func__);
- } else {
- ql_dbg(ql_dbg_disc, vha, 0x2012,
- "%s success\n", __func__);
- }
-
return(rval);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 0a5c8951cebb..28c38b4929ce 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -83,7 +83,7 @@ static inline void
host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
{
uint32_t *isrc = (uint32_t *) src;
- uint32_t *odest = (uint32_t *) dst;
+ __le32 *odest = (__le32 *) dst;
uint32_t iter = bsize >> 2;
for (; iter ; iter--)
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 15e4080b347c..42ef481db942 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1189,7 +1189,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
uint32_t *cur_dsd, *fcp_dl;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
- struct scatterlist *cur_seg;
int sgc;
uint32_t total_bytes = 0;
uint32_t data_bytes;
@@ -1396,7 +1395,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
if (bundling && tot_prot_dsds) {
/* Walks dif segments */
- cur_seg = scsi_prot_sglist(cmd);
cmd_pkt->control_flags |=
__constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
@@ -1863,8 +1861,8 @@ skip_cmd_array:
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
if (IS_QLAFX00(ha)) {
- WRT_REG_BYTE(&pkt->entry_count, req_cnt);
- WRT_REG_WORD(&pkt->handle, handle);
+ WRT_REG_BYTE((void __iomem *)&pkt->entry_count, req_cnt);
+ WRT_REG_WORD((void __iomem *)&pkt->handle, handle);
} else {
pkt->entry_count = req_cnt;
pkt->handle = handle;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d2a4c75e5b8f..2d8e7b812352 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2485,6 +2485,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
if (rval == QLA_SUCCESS)
goto next_test;
+ rval = QLA_SUCCESS;
WRT_REG_DWORD(&reg->iobase_window, 0x0003);
for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
rval == QLA_SUCCESS; cnt--) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 3587ec267fa6..7257c3c4f2d0 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -177,8 +177,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
-
+ if (!wait_for_completion_timeout(&ha->mbx_intr_comp,
+ mcp->tov * HZ)) {
+ ql_dbg(ql_dbg_mbx, vha, 0x117a,
+ "cmd=%x Timeout.\n", command);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
} else {
ql_dbg(ql_dbg_mbx, vha, 0x1011,
"Cmd=%x Polling Mode.\n", command);
@@ -275,9 +281,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
/*
* Attempt to capture a firmware dump for further analysis
- * of the current firmware state
+ * of the current firmware state. We do not need to do this
+ * if we are intentionally generating a dump.
*/
- ha->isp_ops->fw_dump(vha, 0);
+ if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
+ ha->isp_ops->fw_dump(vha, 0);
rval = QLA_FUNCTION_TIMEOUT;
}
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index a6df55838365..d7993797f46e 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -707,7 +707,7 @@ qlafx00_tmf_iocb_timeout(void *data)
srb_t *sp = (srb_t *)data;
struct srb_iocb *tmf = &sp->u.iocb_cmd;
- tmf->u.tmf.comp_status = CS_TIMEOUT;
+ tmf->u.tmf.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
complete(&tmf->u.tmf.comp);
}
@@ -1418,7 +1418,8 @@ qlafx00_init_response_q_entries(struct rsp_que *rsp)
pkt = rsp->ring_ptr;
for (cnt = 0; cnt < rsp->length; cnt++) {
pkt->signature = RESPONSE_PROCESSED;
- WRT_REG_DWORD(&pkt->signature, RESPONSE_PROCESSED);
+ WRT_REG_DWORD((void __iomem *)&pkt->signature,
+ RESPONSE_PROCESSED);
pkt++;
}
}
@@ -1733,7 +1734,7 @@ qla2x00_fxdisc_sp_done(void *data, void *ptr, int res)
}
int
-qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
+qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
{
srb_t *sp;
struct srb_iocb *fdisc;
@@ -1759,13 +1760,13 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
fdisc->u.fxiocb.flags =
SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
- fdisc->u.fxiocb.req_data = fcport->port_id;
+ fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->port_id);
break;
case FXDISC_GET_TGT_NODE_INFO:
fdisc->u.fxiocb.flags =
SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
- fdisc->u.fxiocb.req_data = fcport->tgt_id;
+ fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->tgt_id);
break;
case FXDISC_GET_TGT_NODE_LIST:
fdisc->u.fxiocb.flags =
@@ -1851,7 +1852,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
sp->name = "fxdisc";
qla2x00_init_timer(sp, FXDISC_TIMEOUT);
fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
- fdisc->u.fxiocb.req_func_type = fx_type;
+ fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type);
sp->done = qla2x00_fxdisc_sp_done;
rval = qla2x00_start_sp(sp);
@@ -1904,7 +1905,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
(uint8_t *)pinfo, 16);
memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
}
- rval = fdisc->u.fxiocb.result;
+ rval = le32_to_cpu(fdisc->u.fxiocb.result);
done_unmap_dma:
if (fdisc->u.fxiocb.rsp_addr)
@@ -1927,7 +1928,7 @@ qlafx00_abort_iocb_timeout(void *data)
srb_t *sp = (srb_t *)data;
struct srb_iocb *abt = &sp->u.iocb_cmd;
- abt->u.abt.comp_status = CS_TIMEOUT;
+ abt->u.abt.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
complete(&abt->u.abt.comp);
}
@@ -2169,14 +2170,14 @@ qlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
static void
qlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
- uint16_t sstatus, uint16_t cpstatus)
+ __le16 sstatus, __le16 cpstatus)
{
struct srb_iocb *tmf;
tmf = &sp->u.iocb_cmd;
- if (cpstatus != CS_COMPLETE ||
- (sstatus & SS_RESPONSE_INFO_LEN_VALID))
- cpstatus = CS_INCOMPLETE;
+ if (cpstatus != cpu_to_le16((uint16_t)CS_COMPLETE) ||
+ (sstatus & cpu_to_le16((uint16_t)SS_RESPONSE_INFO_LEN_VALID)))
+ cpstatus = cpu_to_le16((uint16_t)CS_INCOMPLETE);
tmf->u.tmf.comp_status = cpstatus;
sp->done(vha, sp, 0);
}
@@ -2194,7 +2195,7 @@ qlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
return;
abt = &sp->u.iocb_cmd;
- abt->u.abt.comp_status = le32_to_cpu(pkt->tgt_id_sts);
+ abt->u.abt.comp_status = pkt->tgt_id_sts;
sp->done(vha, sp, 0);
}
@@ -2216,12 +2217,12 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
if (sp->type == SRB_FXIOCB_DCMD) {
iocb_job = &sp->u.iocb_cmd;
- iocb_job->u.fxiocb.seq_number = le32_to_cpu(pkt->seq_no);
- iocb_job->u.fxiocb.fw_flags = le32_to_cpu(pkt->fw_iotcl_flags);
- iocb_job->u.fxiocb.result = le32_to_cpu(pkt->status);
+ iocb_job->u.fxiocb.seq_number = pkt->seq_no;
+ iocb_job->u.fxiocb.fw_flags = pkt->fw_iotcl_flags;
+ iocb_job->u.fxiocb.result = pkt->status;
if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
iocb_job->u.fxiocb.req_data =
- le32_to_cpu(pkt->dataword_r);
+ pkt->dataword_r;
} else {
bsg_job = sp->u.bsg_job;
@@ -2275,10 +2276,10 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
fc_port_t *fcport;
struct scsi_cmnd *cp;
struct sts_entry_fx00 *sts;
- uint16_t comp_status;
- uint16_t scsi_status;
+ __le16 comp_status;
+ __le16 scsi_status;
uint16_t ox_id;
- uint8_t lscsi_status;
+ __le16 lscsi_status;
int32_t resid;
uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
fw_resid_len;
@@ -2292,8 +2293,8 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
sts = (struct sts_entry_fx00 *) pkt;
- comp_status = le16_to_cpu(sts->comp_status);
- scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
+ comp_status = sts->comp_status;
+ scsi_status = sts->scsi_status & cpu_to_le16((uint16_t)SS_MASK);
hindex = sts->handle;
handle = LSW(hindex);
@@ -2339,38 +2340,40 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
- lscsi_status = scsi_status & STATUS_MASK;
+ lscsi_status = scsi_status & cpu_to_le16((uint16_t)STATUS_MASK);
fcport = sp->fcport;
ox_id = 0;
sense_len = par_sense_len = rsp_info_len = resid_len =
fw_resid_len = 0;
- if (scsi_status & SS_SENSE_LEN_VALID)
- sense_len = le32_to_cpu(sts->sense_len);
- if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+ if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))
+ sense_len = sts->sense_len;
+ if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
+ | (uint16_t)SS_RESIDUAL_OVER)))
resid_len = le32_to_cpu(sts->residual_len);
- if (comp_status == CS_DATA_UNDERRUN)
+ if (comp_status == cpu_to_le16((uint16_t)CS_DATA_UNDERRUN))
fw_resid_len = le32_to_cpu(sts->residual_len);
rsp_info = sense_data = sts->data;
par_sense_len = sizeof(sts->data);
/* Check for overrun. */
if (comp_status == CS_COMPLETE &&
- scsi_status & SS_RESIDUAL_OVER)
- comp_status = CS_DATA_OVERRUN;
+ scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_OVER))
+ comp_status = cpu_to_le16((uint16_t)CS_DATA_OVERRUN);
/*
* Based on Host and scsi status generate status code for Linux
*/
- switch (comp_status) {
+ switch (le16_to_cpu(comp_status)) {
case CS_COMPLETE:
case CS_QUEUE_FULL:
if (scsi_status == 0) {
res = DID_OK << 16;
break;
}
- if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
+ if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
+ | (uint16_t)SS_RESIDUAL_OVER))) {
resid = resid_len;
scsi_set_resid(cp, resid);
@@ -2386,19 +2389,20 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
break;
}
}
- res = DID_OK << 16 | lscsi_status;
+ res = DID_OK << 16 | le16_to_cpu(lscsi_status);
- if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ if (lscsi_status ==
+ cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
"QUEUE FULL detected.\n");
break;
}
logit = 0;
- if (lscsi_status != SS_CHECK_CONDITION)
+ if (lscsi_status != cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
break;
memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- if (!(scsi_status & SS_SENSE_LEN_VALID))
+ if (!(scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
break;
qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
@@ -2412,7 +2416,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
else
resid = resid_len;
scsi_set_resid(cp, resid);
- if (scsi_status & SS_RESIDUAL_UNDER) {
+ if (scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_UNDER)) {
if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
&& fw_resid_len != resid_len) {
ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
@@ -2420,7 +2424,8 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
"(0x%x of 0x%x bytes).\n",
resid, scsi_bufflen(cp));
- res = DID_ERROR << 16 | lscsi_status;
+ res = DID_ERROR << 16 |
+ le16_to_cpu(lscsi_status);
goto check_scsi_status;
}
@@ -2436,8 +2441,9 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
res = DID_ERROR << 16;
break;
}
- } else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
- lscsi_status != SAM_STAT_BUSY) {
+ } else if (lscsi_status !=
+ cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL) &&
+ lscsi_status != cpu_to_le16((uint16_t)SAM_STAT_BUSY)) {
/*
* scsi status of task set and busy are considered
* to be task not completed.
@@ -2448,7 +2454,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
"of 0x%x bytes).\n", resid,
scsi_bufflen(cp));
- res = DID_ERROR << 16 | lscsi_status;
+ res = DID_ERROR << 16 | le16_to_cpu(lscsi_status);
goto check_scsi_status;
} else {
ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
@@ -2456,7 +2462,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
scsi_status, lscsi_status);
}
- res = DID_OK << 16 | lscsi_status;
+ res = DID_OK << 16 | le16_to_cpu(lscsi_status);
logit = 0;
check_scsi_status:
@@ -2465,17 +2471,20 @@ check_scsi_status:
* Status.
*/
if (lscsi_status != 0) {
- if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ if (lscsi_status ==
+ cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
"QUEUE FULL detected.\n");
logit = 1;
break;
}
- if (lscsi_status != SS_CHECK_CONDITION)
+ if (lscsi_status !=
+ cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
break;
memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- if (!(scsi_status & SS_SENSE_LEN_VALID))
+ if (!(scsi_status &
+ cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
break;
qlafx00_handle_sense(sp, sense_data, par_sense_len,
@@ -2629,7 +2638,7 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
uint32_t handle, hindex, handle_count, i;
uint16_t que;
struct req_que *req;
- uint32_t *handle_ptr;
+ __le32 *handle_ptr;
stsmfx = (struct multi_sts_entry_fx00 *) pkt;
@@ -2643,7 +2652,7 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
return;
}
- handle_ptr = (uint32_t *) &stsmfx->handles[0];
+ handle_ptr = &stsmfx->handles[0];
for (i = 0; i < handle_count; i++) {
hindex = le32_to_cpu(*handle_ptr);
@@ -2714,10 +2723,11 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
if (!vha->flags.online)
return;
- while (RD_REG_DWORD(&(rsp->ring_ptr->signature)) !=
+ while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
RESPONSE_PROCESSED) {
lptr = rsp->ring_ptr;
- memcpy_fromio(rsp->rsp_pkt, lptr, sizeof(rsp->rsp_pkt));
+ memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
+ sizeof(rsp->rsp_pkt));
pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
rsp->ring_index++;
@@ -2768,7 +2778,8 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
break;
}
next_iter:
- WRT_REG_DWORD(&lptr->signature, RESPONSE_PROCESSED);
+ WRT_REG_DWORD((void __iomem *)&lptr->signature,
+ RESPONSE_PROCESSED);
wmb();
}
@@ -2958,8 +2969,7 @@ qlafx00_prep_cont_type1_iocb(struct req_que *req,
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
/* Load packet defaults. */
- *((uint32_t *)(&lcont_pkt->entry_type)) =
- __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00);
+ lcont_pkt->entry_type = CONTINUE_A64_TYPE_FX00;
return cont_pkt;
}
@@ -2969,7 +2979,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ __le32 *cur_dsd;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
struct scatterlist *sg;
@@ -2986,8 +2996,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
cont_pkt = NULL;
/* Update entry type to indicate Command Type 3 IOCB */
- *((uint32_t *)(&lcmd_pkt->entry_type)) =
- __constant_cpu_to_le32(FX00_COMMAND_TYPE_7);
+ lcmd_pkt->entry_type = FX00_COMMAND_TYPE_7;
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -3006,7 +3015,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
/* One DSD is available in the Command Type 3 IOCB */
avail_dsds = 1;
- cur_dsd = (uint32_t *)&lcmd_pkt->dseg_0_address;
+ cur_dsd = (__le32 *)&lcmd_pkt->dseg_0_address;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
@@ -3021,7 +3030,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
cont_pkt =
qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
- cur_dsd = (uint32_t *)lcont_pkt.dseg_0_address;
+ cur_dsd = (__le32 *)lcont_pkt.dseg_0_address;
avail_dsds = 5;
cont = 1;
}
@@ -3224,13 +3233,13 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
- if (tm_iocb.control_flags == TCF_LUN_RESET) {
+ if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
int_to_scsilun(fxio->u.tmf.lun, &llun);
host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
sizeof(struct scsi_lun));
}
- memcpy((void __iomem *)ptm_iocb, &tm_iocb,
+ memcpy((void *)ptm_iocb, &tm_iocb,
sizeof(struct tsk_mgmt_entry_fx00));
wmb();
}
@@ -3252,7 +3261,7 @@ qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
abt_iocb.req_que_no = cpu_to_le16(req->id);
- memcpy((void __iomem *)pabt_iocb, &abt_iocb,
+ memcpy((void *)pabt_iocb, &abt_iocb,
sizeof(struct abort_iocb_entry_fx00));
wmb();
}
@@ -3273,13 +3282,12 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
if (sp->type == SRB_FXIOCB_DCMD) {
fx_iocb.func_num =
- cpu_to_le16(sp->u.iocb_cmd.u.fxiocb.req_func_type);
- fx_iocb.adapid = cpu_to_le32(fxio->u.fxiocb.adapter_id);
- fx_iocb.adapid_hi = cpu_to_le32(fxio->u.fxiocb.adapter_id_hi);
- fx_iocb.reserved_0 = cpu_to_le32(fxio->u.fxiocb.reserved_0);
- fx_iocb.reserved_1 = cpu_to_le32(fxio->u.fxiocb.reserved_1);
- fx_iocb.dataword_extra =
- cpu_to_le32(fxio->u.fxiocb.req_data_extra);
+ sp->u.iocb_cmd.u.fxiocb.req_func_type;
+ fx_iocb.adapid = fxio->u.fxiocb.adapter_id;
+ fx_iocb.adapid_hi = fxio->u.fxiocb.adapter_id_hi;
+ fx_iocb.reserved_0 = fxio->u.fxiocb.reserved_0;
+ fx_iocb.reserved_1 = fxio->u.fxiocb.reserved_1;
+ fx_iocb.dataword_extra = fxio->u.fxiocb.req_data_extra;
if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
fx_iocb.req_dsdcnt = cpu_to_le16(1);
@@ -3306,8 +3314,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
}
if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
- fx_iocb.dataword =
- cpu_to_le32(fxio->u.fxiocb.req_data);
+ fx_iocb.dataword = fxio->u.fxiocb.req_data;
}
fx_iocb.flags = fxio->u.fxiocb.flags;
} else {
@@ -3323,21 +3330,21 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
fx_iocb.reserved_1 = piocb_rqst->reserved_1;
fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
fx_iocb.dataword = piocb_rqst->dataword;
- fx_iocb.req_xfrcnt = cpu_to_le16(piocb_rqst->req_len);
- fx_iocb.rsp_xfrcnt = cpu_to_le16(piocb_rqst->rsp_len);
+ fx_iocb.req_xfrcnt = piocb_rqst->req_len;
+ fx_iocb.rsp_xfrcnt = piocb_rqst->rsp_len;
if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
int avail_dsds, tot_dsds;
cont_a64_entry_t lcont_pkt;
cont_a64_entry_t *cont_pkt = NULL;
- uint32_t *cur_dsd;
+ __le32 *cur_dsd;
int index = 0, cont = 0;
fx_iocb.req_dsdcnt =
cpu_to_le16(bsg_job->request_payload.sg_cnt);
tot_dsds =
- cpu_to_le32(bsg_job->request_payload.sg_cnt);
- cur_dsd = (uint32_t *)&fx_iocb.dseg_rq_address[0];
+ bsg_job->request_payload.sg_cnt;
+ cur_dsd = (__le32 *)&fx_iocb.dseg_rq_address[0];
avail_dsds = 1;
for_each_sg(bsg_job->request_payload.sg_list, sg,
tot_dsds, index) {
@@ -3355,7 +3362,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
qlafx00_prep_cont_type1_iocb(
sp->fcport->vha->req,
&lcont_pkt);
- cur_dsd = (uint32_t *)
+ cur_dsd = (__le32 *)
lcont_pkt.dseg_0_address;
avail_dsds = 5;
cont = 1;
@@ -3393,13 +3400,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
int avail_dsds, tot_dsds;
cont_a64_entry_t lcont_pkt;
cont_a64_entry_t *cont_pkt = NULL;
- uint32_t *cur_dsd;
+ __le32 *cur_dsd;
int index = 0, cont = 0;
fx_iocb.rsp_dsdcnt =
cpu_to_le16(bsg_job->reply_payload.sg_cnt);
- tot_dsds = cpu_to_le32(bsg_job->reply_payload.sg_cnt);
- cur_dsd = (uint32_t *)&fx_iocb.dseg_rsp_address[0];
+ tot_dsds = bsg_job->reply_payload.sg_cnt;
+ cur_dsd = (__le32 *)&fx_iocb.dseg_rsp_address[0];
avail_dsds = 1;
for_each_sg(bsg_job->reply_payload.sg_list, sg,
@@ -3418,7 +3425,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
qlafx00_prep_cont_type1_iocb(
sp->fcport->vha->req,
&lcont_pkt);
- cur_dsd = (uint32_t *)
+ cur_dsd = (__le32 *)
lcont_pkt.dseg_0_address;
avail_dsds = 5;
cont = 1;
@@ -3453,7 +3460,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
}
if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
- fx_iocb.dataword = cpu_to_le32(piocb_rqst->dataword);
+ fx_iocb.dataword = piocb_rqst->dataword;
fx_iocb.flags = piocb_rqst->flags;
fx_iocb.entry_count = entry_cnt;
}
@@ -3462,7 +3469,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
sp->fcport->vha, 0x3047,
(uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00));
- memcpy((void __iomem *)pfxiocb, &fx_iocb,
+ memcpy((void *)pfxiocb, &fx_iocb,
sizeof(struct fxdisc_entry_fx00));
wmb();
}
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index cc327dc2fd10..1a092af0e2c3 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -24,10 +24,10 @@ struct cmd_type_7_fx00 {
uint32_t handle; /* System handle. */
uint32_t handle_hi;
- uint16_t tgt_idx; /* Target Idx. */
+ __le16 tgt_idx; /* Target Idx. */
uint16_t timeout; /* Command timeout. */
- uint16_t dseg_count; /* Data segment count. */
+ __le16 dseg_count; /* Data segment count. */
uint16_t scsi_rsp_dsd_len;
struct scsi_lun lun; /* LUN (LE). */
@@ -41,7 +41,7 @@ struct cmd_type_7_fx00 {
uint8_t crn;
uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
- uint32_t byte_count; /* Total byte count. */
+ __le32 byte_count; /* Total byte count. */
uint32_t dseg_0_address[2]; /* Data segment 0 address. */
uint32_t dseg_0_len; /* Data segment 0 length. */
@@ -81,16 +81,16 @@ struct sts_entry_fx00 {
uint32_t handle; /* System handle. */
uint32_t handle_hi; /* System handle. */
- uint16_t comp_status; /* Completion status. */
+ __le16 comp_status; /* Completion status. */
uint16_t reserved_0; /* OX_ID used by the firmware. */
- uint32_t residual_len; /* FW calc residual transfer length. */
+ __le32 residual_len; /* FW calc residual transfer length. */
uint16_t reserved_1;
uint16_t state_flags; /* State flags. */
uint16_t reserved_2;
- uint16_t scsi_status; /* SCSI status. */
+ __le16 scsi_status; /* SCSI status. */
uint32_t sense_len; /* FCP SENSE length. */
uint8_t data[32]; /* FCP response/sense information. */
@@ -106,7 +106,7 @@ struct multi_sts_entry_fx00 {
uint8_t handle_count;
uint8_t entry_status;
- uint32_t handles[MAX_HANDLE_COUNT];
+ __le32 handles[MAX_HANDLE_COUNT];
};
#define TSK_MGMT_IOCB_TYPE_FX00 0x05
@@ -116,21 +116,21 @@ struct tsk_mgmt_entry_fx00 {
uint8_t sys_define;
uint8_t entry_status; /* Entry Status. */
- uint32_t handle; /* System handle. */
+ __le32 handle; /* System handle. */
uint32_t handle_hi; /* System handle. */
- uint16_t tgt_id; /* Target Idx. */
+ __le16 tgt_id; /* Target Idx. */
uint16_t reserved_1;
uint16_t delay; /* Activity delay in seconds. */
- uint16_t timeout; /* Command timeout. */
+ __le16 timeout; /* Command timeout. */
struct scsi_lun lun; /* LUN (LE). */
- uint32_t control_flags; /* Control Flags. */
+ __le32 control_flags; /* Control Flags. */
uint8_t reserved_2[32];
};
@@ -143,16 +143,16 @@ struct abort_iocb_entry_fx00 {
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
+ __le32 handle; /* System handle. */
+ __le32 handle_hi; /* System handle. */
- uint16_t tgt_id_sts; /* Completion status. */
- uint16_t options;
+ __le16 tgt_id_sts; /* Completion status. */
+ __le16 options;
- uint32_t abort_handle; /* System handle. */
- uint32_t abort_handle_hi; /* System handle. */
+ __le32 abort_handle; /* System handle. */
+ __le32 abort_handle_hi; /* System handle. */
- uint16_t req_que_no;
+ __le16 req_que_no;
uint8_t reserved_1[38];
};
@@ -167,17 +167,17 @@ struct ioctl_iocb_entry_fx00 {
uint32_t reserved_0; /* System handle. */
uint16_t comp_func_num;
- uint16_t fw_iotcl_flags;
+ __le16 fw_iotcl_flags;
- uint32_t dataword_r; /* Data word returned */
+ __le32 dataword_r; /* Data word returned */
uint32_t adapid; /* Adapter ID */
uint32_t adapid_hi; /* Adapter ID high */
uint32_t reserved_1;
- uint32_t seq_no;
+ __le32 seq_no;
uint8_t reserved_2[20];
uint32_t residuallen;
- uint32_t status;
+ __le32 status;
};
#define STATUS_CONT_TYPE_FX00 0x04
@@ -189,26 +189,26 @@ struct fxdisc_entry_fx00 {
uint8_t sys_define; /* System Defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t handle; /* System handle. */
- uint32_t reserved_0; /* System handle. */
+ __le32 handle; /* System handle. */
+ __le32 reserved_0; /* System handle. */
- uint16_t func_num;
- uint16_t req_xfrcnt;
- uint16_t req_dsdcnt;
- uint16_t rsp_xfrcnt;
- uint16_t rsp_dsdcnt;
+ __le16 func_num;
+ __le16 req_xfrcnt;
+ __le16 req_dsdcnt;
+ __le16 rsp_xfrcnt;
+ __le16 rsp_dsdcnt;
uint8_t flags;
uint8_t reserved_1;
- uint32_t dseg_rq_address[2]; /* Data segment 0 address. */
- uint32_t dseg_rq_len; /* Data segment 0 length. */
- uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */
- uint32_t dseg_rsp_len; /* Data segment 1 length. */
+ __le32 dseg_rq_address[2]; /* Data segment 0 address. */
+ __le32 dseg_rq_len; /* Data segment 0 length. */
+ __le32 dseg_rsp_address[2]; /* Data segment 1 address. */
+ __le32 dseg_rsp_len; /* Data segment 1 length. */
- uint32_t dataword;
- uint32_t adapid;
- uint32_t adapid_hi;
- uint32_t dataword_extra;
+ __le32 dataword;
+ __le32 adapid;
+ __le32 adapid_hi;
+ __le32 dataword_extra;
};
struct qlafx00_tgt_node_info {
@@ -421,43 +421,43 @@ struct config_info_data {
WRT_REG_DWORD((ha)->cregbase + off, val)
struct qla_mt_iocb_rqst_fx00 {
- uint32_t reserved_0;
+ __le32 reserved_0;
- uint16_t func_type;
+ __le16 func_type;
uint8_t flags;
uint8_t reserved_1;
- uint32_t dataword;
+ __le32 dataword;
- uint32_t adapid;
- uint32_t adapid_hi;
+ __le32 adapid;
+ __le32 adapid_hi;
- uint32_t dataword_extra;
+ __le32 dataword_extra;
- uint32_t req_len;
+ __le32 req_len;
- uint32_t rsp_len;
+ __le32 rsp_len;
};
struct qla_mt_iocb_rsp_fx00 {
uint32_t reserved_1;
uint16_t func_type;
- uint16_t ioctl_flags;
+ __le16 ioctl_flags;
- uint32_t ioctl_data;
+ __le32 ioctl_data;
uint32_t adapid;
uint32_t adapid_hi;
uint32_t reserved_2;
- uint32_t seq_number;
+ __le32 seq_number;
uint8_t reserved_3[20];
int32_t res_count;
- uint32_t status;
+ __le32 status;
};
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ad72c1d85111..3e21e9fc9d91 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -104,8 +104,6 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
"Set to control shifting of command type processing "
"based on total number of SG elements.");
-static void qla2x00_free_device(scsi_qla_host_t *);
-
int ql2xfdmienable=1;
module_param(ql2xfdmienable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xfdmienable,
@@ -237,6 +235,7 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
static int qla2x00_change_queue_depth(struct scsi_device *, int, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
+static void qla2x00_free_device(scsi_qla_host_t *);
struct scsi_host_template qla2xxx_driver_template = {
.module = THIS_MODULE,
@@ -2840,8 +2839,7 @@ skip_dpc:
qla2x00_dfs_setup(base_vha);
ql_log(ql_log_info, base_vha, 0x00fb,
- "QLogic %s - %s.\n",
- ha->model_number, ha->model_desc ? ha->model_desc : "");
+ "QLogic %s - %s.\n", ha->model_number, ha->model_desc);
ql_log(ql_log_info, base_vha, 0x00fc,
"ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n",
pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
@@ -2981,14 +2979,12 @@ qla2x00_remove_one(struct pci_dev *pdev)
set_bit(UNLOADING, &base_vha->dpc_flags);
mutex_lock(&ha->vport_lock);
while (ha->cur_vport_count) {
- struct Scsi_Host *scsi_host;
-
spin_lock_irqsave(&ha->vport_slock, flags);
BUG_ON(base_vha->list.next == &ha->vp_list);
/* This assumes first entry in ha->vp_list is always base vha */
vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list);
- scsi_host = scsi_host_get(vha->host);
+ scsi_host_get(vha->host);
spin_unlock_irqrestore(&ha->vport_slock, flags);
mutex_unlock(&ha->vport_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index fcdc22306cab..83a8f7a9ec76 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -544,102 +544,6 @@ out_free_id_list:
return res;
}
-static bool qlt_check_fcport_exist(struct scsi_qla_host *vha,
- struct qla_tgt_sess *sess)
-{
- struct qla_hw_data *ha = vha->hw;
- struct qla_port_24xx_data *pmap24;
- bool res, found = false;
- int rc, i;
- uint16_t loop_id = 0xFFFF; /* to eliminate compiler's warning */
- uint16_t entries;
- void *pmap;
- int pmap_len;
- fc_port_t *fcport;
- int global_resets;
- unsigned long flags;
-
-retry:
- global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
-
- rc = qla2x00_get_node_name_list(vha, &pmap, &pmap_len);
- if (rc != QLA_SUCCESS) {
- res = false;
- goto out;
- }
-
- pmap24 = pmap;
- entries = pmap_len/sizeof(*pmap24);
-
- for (i = 0; i < entries; ++i) {
- if (!memcmp(sess->port_name, pmap24[i].port_name, WWN_SIZE)) {
- loop_id = le16_to_cpu(pmap24[i].loop_id);
- found = true;
- break;
- }
- }
-
- kfree(pmap);
-
- if (!found) {
- res = false;
- goto out;
- }
-
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf046,
- "qlt_check_fcport_exist(): loop_id %d", loop_id);
-
- fcport = kzalloc(sizeof(*fcport), GFP_KERNEL);
- if (fcport == NULL) {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf047,
- "qla_target(%d): Allocation of tmp FC port failed",
- vha->vp_idx);
- res = false;
- goto out;
- }
-
- fcport->loop_id = loop_id;
-
- rc = qla2x00_get_port_database(vha, fcport, 0);
- if (rc != QLA_SUCCESS) {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf048,
- "qla_target(%d): Failed to retrieve fcport "
- "information -- get_port_database() returned %x "
- "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id);
- res = false;
- goto out_free_fcport;
- }
-
- if (global_resets !=
- atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002,
- "qla_target(%d): global reset during session discovery"
- " (counter was %d, new %d), retrying",
- vha->vp_idx, global_resets,
- atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count));
- goto retry;
- }
-
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003,
- "Updating sess %p s_id %x:%x:%x, loop_id %d) to d_id %x:%x:%x, "
- "loop_id %d", sess, sess->s_id.b.domain, sess->s_id.b.al_pa,
- sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain,
- fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id);
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
- (fcport->flags & FCF_CONF_COMP_SUPPORTED));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
- res = true;
-
-out_free_fcport:
- kfree(fcport);
-
-out:
- return res;
-}
-
/* ha->hardware_lock supposed to be held on entry */
static void qlt_undelete_sess(struct qla_tgt_sess *sess)
{
@@ -663,43 +567,13 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
del_list_entry);
if (time_after_eq(jiffies, sess->expires)) {
- bool cancel;
-
qlt_undelete_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- cancel = qlt_check_fcport_exist(vha, sess);
-
- if (cancel) {
- if (sess->deleted) {
- /*
- * sess was again deleted while we were
- * discovering it
- */
- spin_lock_irqsave(&ha->hardware_lock,
- flags);
- continue;
- }
-
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf049,
- "qla_target(%d): cancel deletion of "
- "session for port %02x:%02x:%02x:%02x:%02x:"
- "%02x:%02x:%02x (loop ID %d), because "
- " it isn't deleted by firmware",
- vha->vp_idx, sess->port_name[0],
- sess->port_name[1], sess->port_name[2],
- sess->port_name[3], sess->port_name[4],
- sess->port_name[5], sess->port_name[6],
- sess->port_name[7], sess->loop_id);
- } else {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
- "Timeout: sess %p about to be deleted\n",
- sess);
- ha->tgt.tgt_ops->shutdown_sess(sess);
- ha->tgt.tgt_ops->put_sess(sess);
- }
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
+ "Timeout: sess %p about to be deleted\n",
+ sess);
+ ha->tgt.tgt_ops->shutdown_sess(sess);
+ ha->tgt.tgt_ops->put_sess(sess);
} else {
schedule_delayed_work(&tgt->sess_del_work,
jiffies - sess->expires);
@@ -884,9 +758,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
sess->loop_id);
sess->local = 0;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
@@ -2706,7 +2579,9 @@ static void qlt_do_work(struct work_struct *work)
/*
* Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
*/
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
out_term:
@@ -2718,9 +2593,9 @@ out_term:
spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
kmem_cache_free(qla_tgt_cmd_cachep, cmd);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
/* ha->hardware_lock supposed to be held on entry */
@@ -4169,16 +4044,16 @@ static void qlt_abort_work(struct qla_tgt *tgt,
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
if (rc != 0)
goto out_term;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
out_term:
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -4226,16 +4101,16 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
if (rc != 0)
goto out_term;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
out_term:
qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
static void qlt_sess_work_fn(struct work_struct *work)
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 66b0b26a1381..a318092e033f 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -703,7 +703,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
return qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status);
}
-static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
{
struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
@@ -735,8 +735,6 @@ static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
* CTIO response packet.
*/
qlt_xmit_tm_rsp(mcmd);
-
- return 0;
}
/* Local pointer to allocated TCM configfs fabric module */
@@ -799,12 +797,14 @@ static void tcm_qla2xxx_put_session(struct se_session *se_sess)
static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
{
- tcm_qla2xxx_put_session(sess->se_sess);
+ assert_spin_locked(&sess->vha->hw->hardware_lock);
+ kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
}
static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
{
- tcm_qla2xxx_shutdown_session(sess->se_sess);
+ assert_spin_locked(&sess->vha->hw->hardware_lock);
+ target_sess_cmd_list_set_waiting(sess->se_sess);
}
static struct se_node_acl *tcm_qla2xxx_make_nodeacl(
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index d055450c2a4a..cb4fefa1bfba 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -258,7 +258,7 @@ struct sdebug_queued_cmd {
static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
static unsigned char * fake_storep; /* ramdisk storage */
-static unsigned char *dif_storep; /* protection info */
+static struct sd_dif_tuple *dif_storep; /* protection info */
static void *map_storep; /* provisioning map */
static unsigned long map_size;
@@ -277,11 +277,6 @@ static char sdebug_proc_name[] = "scsi_debug";
static struct bus_type pseudo_lld_bus;
-static inline sector_t dif_offset(sector_t sector)
-{
- return sector << 3;
-}
-
static struct device_driver sdebug_driverfs_driver = {
.name = sdebug_proc_name,
.bus = &pseudo_lld_bus,
@@ -1736,6 +1731,50 @@ static int do_device_access(struct scsi_cmnd *scmd,
return ret;
}
+static u16 dif_compute_csum(const void *buf, int len)
+{
+ u16 csum;
+
+ switch (scsi_debug_guard) {
+ case 1:
+ csum = ip_compute_csum(buf, len);
+ break;
+ case 0:
+ csum = cpu_to_be16(crc_t10dif(buf, len));
+ break;
+ }
+ return csum;
+}
+
+static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
+ sector_t sector, u32 ei_lba)
+{
+ u16 csum = dif_compute_csum(data, scsi_debug_sector_size);
+
+ if (sdt->guard_tag != csum) {
+ pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
+ __func__,
+ (unsigned long)sector,
+ be16_to_cpu(sdt->guard_tag),
+ be16_to_cpu(csum));
+ return 0x01;
+ }
+ if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
+ be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
+ pr_err("%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ return 0x03;
+ }
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ be32_to_cpu(sdt->ref_tag) != ei_lba) {
+ pr_err("%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ dif_errors++;
+ return 0x03;
+ }
+ return 0;
+}
+
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
@@ -1748,71 +1787,38 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
start_sec = do_div(tmp_sec, sdebug_store_sectors);
- sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
+ sdt = dif_storep + start_sec;
for (i = 0 ; i < sectors ; i++) {
- u16 csum;
+ int ret;
if (sdt[i].app_tag == 0xffff)
continue;
sector = start_sec + i;
- switch (scsi_debug_guard) {
- case 1:
- csum = ip_compute_csum(fake_storep +
- sector * scsi_debug_sector_size,
- scsi_debug_sector_size);
- break;
- case 0:
- csum = crc_t10dif(fake_storep +
- sector * scsi_debug_sector_size,
- scsi_debug_sector_size);
- csum = cpu_to_be16(csum);
- break;
- default:
- BUG();
- }
-
- if (sdt[i].guard_tag != csum) {
- printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
- " rcvd 0x%04x, data 0x%04x\n", __func__,
- (unsigned long)sector,
- be16_to_cpu(sdt[i].guard_tag),
- be16_to_cpu(csum));
- dif_errors++;
- return 0x01;
- }
-
- if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
- be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
- printk(KERN_ERR "%s: REF check failed on sector %lu\n",
- __func__, (unsigned long)sector);
+ ret = dif_verify(&sdt[i],
+ fake_storep + sector * scsi_debug_sector_size,
+ sector, ei_lba);
+ if (ret) {
dif_errors++;
- return 0x03;
- }
-
- if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
- be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
- printk(KERN_ERR "%s: REF check failed on sector %lu\n",
- __func__, (unsigned long)sector);
- dif_errors++;
- return 0x03;
+ return ret;
}
ei_lba++;
}
- resid = sectors * 8; /* Bytes of protection data to copy into sgl */
+ /* Bytes of protection data to copy into sgl */
+ resid = sectors * sizeof(*dif_storep);
sector = start_sec;
scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
int len = min(psgl->length, resid);
paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
- memcpy(paddr, dif_storep + dif_offset(sector), len);
+ memcpy(paddr, dif_storep + sector, len);
- sector += len >> 3;
+ sector += len / sizeof(*dif_storep);
if (sector >= sdebug_store_sectors) {
/* Force wrap */
tmp_sec = sector;
@@ -1910,22 +1916,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sector_t tmp_sec = start_sec;
sector_t sector;
int ppage_offset;
- unsigned short csum;
sector = do_div(tmp_sec, sdebug_store_sectors);
BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
- paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
ppage_offset = 0;
/* For each data page */
scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
+ paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
/* For each sector-sized chunk in data page */
- for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
+ for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
/* If we're at the end of the current
* protection page advance to the next one
@@ -1941,51 +1946,9 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sdt = paddr + ppage_offset;
- switch (scsi_debug_guard) {
- case 1:
- csum = ip_compute_csum(daddr,
- scsi_debug_sector_size);
- break;
- case 0:
- csum = cpu_to_be16(crc_t10dif(daddr,
- scsi_debug_sector_size));
- break;
- default:
- BUG();
- ret = 0;
- goto out;
- }
-
- if (sdt->guard_tag != csum) {
- printk(KERN_ERR
- "%s: GUARD check failed on sector %lu " \
- "rcvd 0x%04x, calculated 0x%04x\n",
- __func__, (unsigned long)sector,
- be16_to_cpu(sdt->guard_tag),
- be16_to_cpu(csum));
- ret = 0x01;
- dump_sector(daddr, scsi_debug_sector_size);
- goto out;
- }
-
- if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
- be32_to_cpu(sdt->ref_tag)
- != (start_sec & 0xffffffff)) {
- printk(KERN_ERR
- "%s: REF check failed on sector %lu\n",
- __func__, (unsigned long)sector);
- ret = 0x03;
- dump_sector(daddr, scsi_debug_sector_size);
- goto out;
- }
-
- if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
- be32_to_cpu(sdt->ref_tag) != ei_lba) {
- printk(KERN_ERR
- "%s: REF check failed on sector %lu\n",
- __func__, (unsigned long)sector);
- ret = 0x03;
- dump_sector(daddr, scsi_debug_sector_size);
+ ret = dif_verify(sdt, daddr + j, start_sec, ei_lba);
+ if (ret) {
+ dump_sector(daddr + j, scsi_debug_sector_size);
goto out;
}
@@ -1994,7 +1957,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
* correctness we need to verify each sector
* before writing it to "stable" storage
*/
- memcpy(dif_storep + dif_offset(sector), sdt, 8);
+ memcpy(dif_storep + sector, sdt, sizeof(*sdt));
sector++;
@@ -2003,23 +1966,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
start_sec++;
ei_lba++;
- daddr += scsi_debug_sector_size;
ppage_offset += sizeof(struct sd_dif_tuple);
}
+ kunmap_atomic(paddr);
kunmap_atomic(daddr);
}
- kunmap_atomic(paddr);
-
dix_writes++;
return 0;
out:
dif_errors++;
- kunmap_atomic(daddr);
kunmap_atomic(paddr);
+ kunmap_atomic(daddr);
return ret;
}
@@ -2092,6 +2053,11 @@ static void unmap_region(sector_t lba, unsigned int len)
scsi_debug_sector_size *
scsi_debug_unmap_granularity);
}
+ if (dif_storep) {
+ memset(dif_storep + lba, 0xff,
+ sizeof(*dif_storep) *
+ scsi_debug_unmap_granularity);
+ }
}
lba = map_index_to_lba(index + 1);
}
@@ -3400,7 +3366,7 @@ static int __init scsi_debug_init(void)
if (scsi_debug_num_parts > 0)
sdebug_build_parts(fake_storep, sz);
- if (scsi_debug_dif) {
+ if (scsi_debug_dix) {
int dif_size;
dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 86d522004a20..124392f3091e 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -434,6 +434,8 @@ static void scsi_run_queue(struct request_queue *q)
list_splice_init(&shost->starved_list, &starved_list);
while (!list_empty(&starved_list)) {
+ struct request_queue *slq;
+
/*
* As long as shost is accepting commands and we have
* starved queues, call blk_run_queue. scsi_request_fn
@@ -456,11 +458,25 @@ static void scsi_run_queue(struct request_queue *q)
continue;
}
- spin_unlock(shost->host_lock);
- spin_lock(sdev->request_queue->queue_lock);
- __blk_run_queue(sdev->request_queue);
- spin_unlock(sdev->request_queue->queue_lock);
- spin_lock(shost->host_lock);
+ /*
+ * Once we drop the host lock, a racing scsi_remove_device()
+ * call may remove the sdev from the starved list and destroy
+ * it and the queue. Mitigate by taking a reference to the
+ * queue and never touching the sdev again after we drop the
+ * host lock. Note: if __scsi_remove_device() invokes
+ * blk_cleanup_queue() before the queue is run from this
+ * function then blk_run_queue() will return immediately since
+ * blk_cleanup_queue() marks the queue with QUEUE_FLAG_DYING.
+ */
+ slq = sdev->request_queue;
+ if (!blk_get_queue(slq))
+ continue;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ blk_run_queue(slq);
+ blk_put_queue(slq);
+
+ spin_lock_irqsave(shost->host_lock, flags);
}
/* put any unprocessed entries back */
list_splice(&starved_list, &shost->starved_list);
@@ -2177,6 +2193,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_OFFLINE:
case SDEV_TRANSPORT_OFFLINE:
case SDEV_CANCEL:
+ case SDEV_CREATED_BLOCK:
break;
default:
goto illegal;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 945198910460..83ec1aa85964 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -326,7 +326,9 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
*/
static int storvsc_timeout = 180;
-#define STORVSC_MAX_IO_REQUESTS 128
+#define STORVSC_MAX_IO_REQUESTS 200
+
+static void storvsc_on_channel_callback(void *context);
/*
* In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
@@ -364,6 +366,7 @@ struct storvsc_device {
bool destroy;
bool drain_notify;
+ bool open_sub_channel;
atomic_t num_outstanding_req;
struct Scsi_Host *host;
@@ -755,12 +758,104 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
return total_copied;
}
+static void handle_sc_creation(struct vmbus_channel *new_sc)
+{
+ struct hv_device *device = new_sc->primary_channel->device_obj;
+ struct storvsc_device *stor_device;
+ struct vmstorage_channel_properties props;
+
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return;
+
+ if (stor_device->open_sub_channel == false)
+ return;
+
+ memset(&props, 0, sizeof(struct vmstorage_channel_properties));
+
+ vmbus_open(new_sc,
+ storvsc_ringbuffer_size,
+ storvsc_ringbuffer_size,
+ (void *)&props,
+ sizeof(struct vmstorage_channel_properties),
+ storvsc_on_channel_callback, new_sc);
+}
+
+static void handle_multichannel_storage(struct hv_device *device, int max_chns)
+{
+ struct storvsc_device *stor_device;
+ int num_cpus = num_online_cpus();
+ int num_sc;
+ struct storvsc_cmd_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
+ num_sc = ((max_chns > num_cpus) ? num_cpus : max_chns);
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return;
+
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
+
+ stor_device->open_sub_channel = true;
+ /*
+ * Establish a handler for dealing with subchannels.
+ */
+ vmbus_set_sc_create_callback(device->channel, handle_sc_creation);
+
+ /*
+ * Check to see if sub-channels have already been created. This
+ * can happen when this driver is re-loaded after unloading.
+ */
+
+ if (vmbus_are_subchannels_present(device->channel))
+ return;
+
+ stor_device->open_sub_channel = false;
+ /*
+ * Request the host to create sub-channels.
+ */
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
+ init_completion(&request->wait_event);
+ vstor_packet->operation = VSTOR_OPERATION_CREATE_SUB_CHANNELS;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->sub_channel_count = num_sc;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ (sizeof(struct vstor_packet) -
+ vmscsi_size_delta),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+ if (ret != 0)
+ return;
+
+ t = wait_for_completion_timeout(&request->wait_event, 10*HZ);
+ if (t == 0)
+ return;
+
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0)
+ return;
+
+ /*
+ * Now that we created the sub-channels, invoke the check; this
+ * may trigger the callback.
+ */
+ stor_device->open_sub_channel = true;
+ vmbus_are_subchannels_present(device->channel);
+}
+
static int storvsc_channel_init(struct hv_device *device)
{
struct storvsc_device *stor_device;
struct storvsc_cmd_request *request;
struct vstor_packet *vstor_packet;
int ret, t;
+ int max_chns;
+ bool process_sub_channels = false;
stor_device = get_out_stor_device(device);
if (!stor_device)
@@ -855,6 +950,19 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet->status != 0)
goto cleanup;
+ /*
+ * Check to see if multi-channel support is there.
+ * Hosts that implement protocol version of 5.1 and above
+ * support multi-channel.
+ */
+ max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
+ if ((vmbus_proto_version != VERSION_WIN7) &&
+ (vmbus_proto_version != VERSION_WS2008)) {
+ if (vstor_packet->storage_channel_properties.flags &
+ STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
+ process_sub_channels = true;
+ }
+
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
@@ -879,6 +987,9 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet->status != 0)
goto cleanup;
+ if (process_sub_channels)
+ handle_multichannel_storage(device, max_chns);
+
cleanup:
return ret;
@@ -1100,7 +1211,8 @@ static void storvsc_on_receive(struct hv_device *device,
static void storvsc_on_channel_callback(void *context)
{
- struct hv_device *device = (struct hv_device *)context;
+ struct vmbus_channel *channel = (struct vmbus_channel *)context;
+ struct hv_device *device;
struct storvsc_device *stor_device;
u32 bytes_recvd;
u64 request_id;
@@ -1108,13 +1220,17 @@ static void storvsc_on_channel_callback(void *context)
struct storvsc_cmd_request *request;
int ret;
+ if (channel->primary_channel != NULL)
+ device = channel->primary_channel->device_obj;
+ else
+ device = channel->device_obj;
stor_device = get_in_stor_device(device);
if (!stor_device)
return;
do {
- ret = vmbus_recvpacket(device->channel, packet,
+ ret = vmbus_recvpacket(channel, packet,
ALIGN((sizeof(struct vstor_packet) -
vmscsi_size_delta), 8),
&bytes_recvd, &request_id);
@@ -1155,7 +1271,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
ring_size,
(void *)&props,
sizeof(struct vmstorage_channel_properties),
- storvsc_on_channel_callback, device);
+ storvsc_on_channel_callback, device->channel);
if (ret != 0)
return ret;
@@ -1207,6 +1323,7 @@ static int storvsc_do_io(struct hv_device *device,
{
struct storvsc_device *stor_device;
struct vstor_packet *vstor_packet;
+ struct vmbus_channel *outgoing_channel;
int ret = 0;
vstor_packet = &request->vstor_packet;
@@ -1217,6 +1334,11 @@ static int storvsc_do_io(struct hv_device *device,
request->device = device;
+ /*
+ * Select an an appropriate channel to send the request out.
+ */
+
+ outgoing_channel = vmbus_get_outgoing_channel(device->channel);
vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
@@ -1234,7 +1356,7 @@ static int storvsc_do_io(struct hv_device *device,
vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
if (request->data_buffer.len) {
- ret = vmbus_sendpacket_multipagebuffer(device->channel,
+ ret = vmbus_sendpacket_multipagebuffer(outgoing_channel,
&request->data_buffer,
vstor_packet,
(sizeof(struct vstor_packet) -
@@ -1580,6 +1702,7 @@ static struct scsi_host_template scsi_driver = {
enum {
SCSI_GUID,
IDE_GUID,
+ SFC_GUID,
};
static const struct hv_vmbus_device_id id_table[] = {
@@ -1591,6 +1714,11 @@ static const struct hv_vmbus_device_id id_table[] = {
{ HV_IDE_GUID,
.driver_data = IDE_GUID
},
+ /* Fibre Channel GUID */
+ {
+ HV_SYNTHFC_GUID,
+ .driver_data = SFC_GUID
+ },
{ },
};
@@ -1643,6 +1771,7 @@ static int storvsc_probe(struct hv_device *device,
}
stor_device->destroy = false;
+ stor_device->open_sub_channel = false;
init_waitqueue_head(&stor_device->waiting_to_drain);
stor_device->device = device;
stor_device->host = host;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 10f99f45a29b..89cbbabaff44 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -266,7 +266,7 @@ config SPI_OC_TINY
config SPI_OCTEON
tristate "Cavium OCTEON SPI controller"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
help
SPI host driver for the hardware found on some Cavium OCTEON
SOCs.
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 5ff3a4f19443..36171fd2826b 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -144,7 +144,7 @@ config SSB_SFLASH
# Assumption: We are on embedded, if we compile the MIPS core.
config SSB_EMBEDDED
bool
- depends on SSB_DRIVER_MIPS
+ depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
default y
config SSB_DRIVER_EXTIF
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index f64b662c74db..3227ebeae3f1 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -120,8 +120,6 @@ source "drivers/staging/gdm72xx/Kconfig"
source "drivers/staging/csr/Kconfig"
-source "drivers/staging/ti-soc-thermal/Kconfig"
-
source "drivers/staging/silicom/Kconfig"
source "drivers/staging/ced1401/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 1fb58a1562cb..4d79ebe2de06 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,7 +53,6 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_CSR_WIFI) += csr/
-obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 05673ed45ce4..766a071b0a22 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -1751,10 +1751,10 @@ static const struct media_entity_operations ipipe_media_ops = {
*/
void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *vpfe_ipipe)
{
- /* cleanup entity */
- media_entity_cleanup(&vpfe_ipipe->subdev.entity);
/* unregister subdev */
v4l2_device_unregister_subdev(&vpfe_ipipe->subdev);
+ /* cleanup entity */
+ media_entity_cleanup(&vpfe_ipipe->subdev.entity);
}
/*
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
index b2f4ef84f3db..59540cd4bb98 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
@@ -947,10 +947,10 @@ void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
/* unregister video device */
vpfe_video_unregister(&ipipeif->video_in);
- /* cleanup entity */
- media_entity_cleanup(&ipipeif->subdev.entity);
/* unregister subdev */
v4l2_device_unregister_subdev(&ipipeif->subdev);
+ /* cleanup entity */
+ media_entity_cleanup(&ipipeif->subdev.entity);
}
int
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 5829360f74c9..ff48fce94fcb 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -1750,10 +1750,10 @@ static const struct media_entity_operations isif_media_ops = {
void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
{
vpfe_video_unregister(&isif->video_out);
- /* cleanup entity */
- media_entity_cleanup(&isif->subdev.entity);
/* unregister subdev */
v4l2_device_unregister_subdev(&isif->subdev);
+ /* cleanup entity */
+ media_entity_cleanup(&isif->subdev.entity);
}
static void isif_restore_defaults(struct vpfe_isif_device *isif)
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index 126f84c4cb64..8e13bd494c98 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -1777,14 +1777,14 @@ void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
- /* cleanup entity */
- media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
- media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
- media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
/* unregister subdev */
v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
+ /* cleanup entity */
+ media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
+ media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
+ media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
}
/*
@@ -1865,12 +1865,12 @@ out_create_link:
vpfe_video_unregister(&resizer->resizer_b.video_out);
out_video_out2_register:
vpfe_video_unregister(&resizer->resizer_a.video_out);
- media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
- media_entity_cleanup(&resizer->resizer_a.subdev.entity);
- media_entity_cleanup(&resizer->resizer_b.subdev.entity);
v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
+ media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
+ media_entity_cleanup(&resizer->resizer_a.subdev.entity);
+ media_entity_cleanup(&resizer->resizer_b.subdev.entity);
return ret;
}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index ba913f1d955b..24d98a6866bb 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -39,7 +39,7 @@ static struct media_entity *vpfe_get_input_entity
struct vpfe_device *vpfe_dev = video->vpfe_dev;
struct media_pad *remote;
- remote = media_entity_remote_source(&vpfe_dev->vpfe_isif.pads[0]);
+ remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
if (remote == NULL) {
pr_err("Invalid media connection to isif/ccdc\n");
return NULL;
@@ -56,7 +56,7 @@ static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
struct media_pad *remote;
int i;
- remote = media_entity_remote_source(&vpfe_dev->vpfe_isif.pads[0]);
+ remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
if (remote == NULL) {
pr_err("Invalid media connection to isif/ccdc\n");
return -EINVAL;
@@ -89,7 +89,7 @@ static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
static struct v4l2_subdev *
vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
{
- struct media_pad *remote = media_entity_remote_source(&video->pad);
+ struct media_pad *remote = media_entity_remote_pad(&video->pad);
if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
return NULL;
@@ -114,7 +114,7 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
return -EINVAL;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- remote = media_entity_remote_source(&video->pad);
+ remote = media_entity_remote_pad(&video->pad);
fmt.pad = remote->index;
ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
@@ -245,7 +245,7 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
return -EPIPE;
/* Retrieve the source format */
- pad = media_entity_remote_source(pad);
+ pad = media_entity_remote_pad(pad);
if (pad == NULL ||
pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
break;
@@ -667,7 +667,7 @@ static int vpfe_enum_fmt(struct file *file, void *priv,
return -EINVAL;
}
/* get the remote pad */
- remote = media_entity_remote_source(&video->pad);
+ remote = media_entity_remote_pad(&video->pad);
if (remote == NULL) {
v4l2_err(&vpfe_dev->v4l2_dev,
"invalid remote pad for video node\n");
@@ -1614,7 +1614,7 @@ int vpfe_video_register(struct vpfe_video_device *video,
void vpfe_video_unregister(struct vpfe_video_device *video)
{
if (video_is_registered(&video->video_dev)) {
- media_entity_cleanup(&video->video_dev.entity);
video_unregister_device(&video->video_dev);
+ media_entity_cleanup(&video->video_dev.entity);
}
}
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index c32e0acde4f4..90d6ac469355 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -829,7 +829,6 @@ static struct video_device dt3155_vdev = {
.minor = -1,
.release = video_device_release,
.tvnorms = DT3155_CURRENT_NORM,
- .current_norm = DT3155_CURRENT_NORM,
};
/* same as in drivers/base/dma-coherent.c */
diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c
index 50066e01a6ed..46ed83245035 100644
--- a/drivers/staging/media/go7007/go7007-usb.c
+++ b/drivers/staging/media/go7007/go7007-usb.c
@@ -1124,7 +1124,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
case GO7007_BOARDID_LIFEVIEW_LR192:
printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
"is not supported. Sorry!\n");
- return 0;
+ return -ENODEV;
name = "Lifeview TV Walker Ultra";
board = &board_lifeview_lr192;
break;
@@ -1140,7 +1140,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
default:
printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
(unsigned int)id->driver_info);
- return 0;
+ return -ENODEV;
}
go = go7007_alloc(&board->main_info, &intf->dev);
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 0a2c45dd4475..4afa7da11f37 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -911,8 +911,8 @@ static int imon_probe(struct usb_interface *interface,
if (retval) {
dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n",
__func__, retval);
- mutex_unlock(&context->ctx_lock);
- goto exit;
+ alloc_status = 8;
+ goto unlock;
}
usb_set_intfdata(interface, context);
@@ -937,6 +937,8 @@ unlock:
alloc_status_switch:
switch (alloc_status) {
+ case 8:
+ lirc_unregister_driver(driver->minor);
case 7:
usb_free_urb(tx_urb);
case 6:
@@ -959,7 +961,6 @@ alloc_status_switch:
retval = 0;
}
-exit:
mutex_unlock(&driver_lock);
return retval;
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.c b/drivers/staging/media/solo6x10/solo6x10-tw28.c
index ad00e2b60323..af65ea655f15 100644
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.c
+++ b/drivers/staging/media/solo6x10/solo6x10-tw28.c
@@ -513,62 +513,82 @@ static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
#define FIRST_ACTIVE_LINE 0x0008
#define LAST_ACTIVE_LINE 0x0102
-static void saa7128_setup(struct solo_dev *solo_dev)
+static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
+ int start, int n)
{
- int i;
- unsigned char regs[128] = {
- 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ for (;start < n; start++, vals++) {
+ /* Skip read-only registers */
+ switch (start) {
+ /* case 0x00 ... 0x25: */
+ case 0x2e ... 0x37:
+ case 0x60:
+ case 0x7d:
+ continue;
+ }
+ solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals);
+ }
+}
+
+#define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \
+ | ((FIRST_ACTIVE_LINE & 0x100) >> 4))
+
+static void saa712x_setup(struct solo_dev *dev)
+{
+ const int reg_start = 0x26;
+ const uint8_t saa7128_regs_ntsc[] = {
+ /* :0x26 */
+ 0x0d, 0x00,
+ /* :0x28 */
+ 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+ /* :0x2e XXX: read-only */
+ 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
- 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
- 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
+ /* :0x38 */
0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* :0x40 */
0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+ /* :0x50 */
0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+ /* :0x60 */
0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
- 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
+ 0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00,
+ /* :0x70 */
+ 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+ 0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff,
+ SAA712x_reg7c, 0x00, 0xff, 0xff,
+ }, saa7128_regs_pal[] = {
+ /* :0x26 */
+ 0x0d, 0x00,
+ /* :0x28 */
+ 0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+ /* :0x2e XXX: read-only */
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* :0x38 */
+ 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* :0x40 */
+ 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+ 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+ /* :0x50 */
+ 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+ 0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+ /* :0x60 */
+ 0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77,
+ 0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00,
+ /* :0x70 */
0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
- 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x12, 0x30,
+ SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff,
};
- regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
- regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
- regs[0x7C] = ((1 << 7) |
- (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
- (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
-
- /* PAL: XXX: We could do a second set of regs to avoid this */
- if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
- regs[0x28] = 0xE1;
-
- regs[0x5A] = 0x0F;
- regs[0x61] = 0x02;
- regs[0x62] = 0x35;
- regs[0x63] = 0xCB;
- regs[0x64] = 0x8A;
- regs[0x65] = 0x09;
- regs[0x66] = 0x2A;
-
- regs[0x6C] = 0xf1;
- regs[0x6E] = 0x20;
-
- regs[0x7A] = 0x06 + 12;
- regs[0x7b] = 0x24 + 12;
- regs[0x7c] |= 1 << 6;
- }
-
- /* First 0x25 bytes are read-only? */
- for (i = 0x26; i < 128; i++) {
- if (i == 0x60 || i == 0x7D)
- continue;
- solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
- }
-
- return;
+ if (dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+ saa712x_write_regs(dev, saa7128_regs_pal, reg_start,
+ sizeof(saa7128_regs_pal));
+ else
+ saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start,
+ sizeof(saa7128_regs_ntsc));
}
int solo_tw28_init(struct solo_dev *solo_dev)
@@ -609,7 +629,7 @@ int solo_tw28_init(struct solo_dev *solo_dev)
return -EINVAL;
}
- saa7128_setup(solo_dev);
+ saa712x_setup(solo_dev);
for (i = 0; i < solo_dev->tw28_cnt; i++) {
if ((solo_dev->tw2865 & (1 << i)))
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index 98e2902afd74..a4c589604b02 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -996,12 +996,11 @@ static int solo_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct solo_enc_dev *solo_enc = video_drvdata(file);
- struct solo_dev *solo_dev = solo_enc->solo_dev;
struct v4l2_captureparm *cp = &sp->parm.capture;
cp->capability = V4L2_CAP_TIMEPERFRAME;
cp->timeperframe.numerator = solo_enc->interval;
- cp->timeperframe.denominator = solo_dev->fps;
+ cp->timeperframe.denominator = solo_enc->solo_dev->fps;
cp->capturemode = 0;
/* XXX: Shouldn't we be able to get/set this from videobuf? */
cp->readbuffers = 2;
@@ -1009,36 +1008,29 @@ static int solo_g_parm(struct file *file, void *priv,
return 0;
}
+static inline int calc_interval(u8 fps, u32 n, u32 d)
+{
+ if (!n || !d)
+ return 1;
+ if (d == fps)
+ return n;
+ n *= fps;
+ return min(15U, n / d + (n % d >= (fps >> 1)));
+}
+
static int solo_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct solo_enc_dev *solo_enc = video_drvdata(file);
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct v4l2_captureparm *cp = &sp->parm.capture;
+ struct v4l2_fract *t = &sp->parm.capture.timeperframe;
+ u8 fps = solo_enc->solo_dev->fps;
if (vb2_is_streaming(&solo_enc->vidq))
return -EBUSY;
- if ((cp->timeperframe.numerator == 0) ||
- (cp->timeperframe.denominator == 0)) {
- /* reset framerate */
- cp->timeperframe.numerator = 1;
- cp->timeperframe.denominator = solo_dev->fps;
- }
-
- if (cp->timeperframe.denominator != solo_dev->fps)
- cp->timeperframe.denominator = solo_dev->fps;
-
- if (cp->timeperframe.numerator > 15)
- cp->timeperframe.numerator = 15;
-
- solo_enc->interval = cp->timeperframe.numerator;
-
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->readbuffers = 2;
-
+ solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
solo_update_mode(solo_enc);
- return 0;
+ return solo_g_parm(file, priv, sp);
}
static long solo_enc_default(struct file *file, void *fh,
diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig
index 9493128e5fd2..6e1d5f8d3ec1 100644
--- a/drivers/staging/octeon/Kconfig
+++ b/drivers/staging/octeon/Kconfig
@@ -1,6 +1,6 @@
config OCTEON_ETHERNET
tristate "Cavium Networks Octeon Ethernet support"
- depends on CPU_CAVIUM_OCTEON && NETDEVICES
+ depends on CAVIUM_OCTEON_SOC && NETDEVICES
select PHYLIB
select MDIO_OCTEON
help
diff --git a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt b/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
deleted file mode 100644
index 1629652372b6..000000000000
--- a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-* Texas Instrument OMAP SCM bandgap bindings
-
-In the System Control Module, OMAP supplies a voltage reference
-and a temperature sensor feature that are gathered in the band
-gap voltage and temperature sensor (VBGAPTS) module. The band
-gap provides current and voltage reference for its internal
-circuits and other analog IP blocks. The analog-to-digital
-converter (ADC) produces an output value that is proportional
-to the silicon temperature.
-
-Required properties:
-- compatible : Should be:
- - "ti,omap4430-bandgap" : for OMAP4430 bandgap
- - "ti,omap4460-bandgap" : for OMAP4460 bandgap
- - "ti,omap4470-bandgap" : for OMAP4470 bandgap
- - "ti,omap5430-bandgap" : for OMAP5430 bandgap
-- interrupts : this entry should indicate which interrupt line
-the talert signal is routed to;
-Specific:
-- ti,tshut-gpio : this entry should be used to inform which GPIO
-line the tshut signal is routed to;
-- regs : this entry must also be specified and it is specific
-to each bandgap version, because the mapping may change from
-soc to soc, apart of depending on available features.
-
-Example:
-OMAP4430:
-bandgap {
- reg = <0x4a002260 0x4 0x4a00232C 0x4>;
- compatible = "ti,omap4430-bandgap";
-};
-
-OMAP4460:
-bandgap {
- reg = <0x4a002260 0x4
- 0x4a00232C 0x4
- 0x4a002378 0x18>;
- compatible = "ti,omap4460-bandgap";
- interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
-};
-
-OMAP4470:
-bandgap {
- reg = <0x4a002260 0x4
- 0x4a00232C 0x4
- 0x4a002378 0x18>;
- compatible = "ti,omap4470-bandgap";
- interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
-};
-
-OMAP5430:
-bandgap {
- reg = <0x4a0021e0 0xc
- 0x4a00232c 0xc
- 0x4a002380 0x2c
- 0x4a0023C0 0x3c>;
- compatible = "ti,omap5430-bandgap";
- interrupts = <0 126 4>; /* talert */
-};
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index d7705e5824fb..f73da43cdf9e 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -628,25 +628,18 @@ static void __exit iscsi_target_cleanup_module(void)
}
static int iscsit_add_reject(
+ struct iscsi_conn *conn,
u8 reason,
- int fail_conn,
- unsigned char *buf,
- struct iscsi_conn *conn)
+ unsigned char *buf)
{
struct iscsi_cmd *cmd;
- struct iscsi_reject *hdr;
- int ret;
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return -1;
cmd->iscsi_opcode = ISCSI_OP_REJECT;
- if (fail_conn)
- cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
-
- hdr = (struct iscsi_reject *) cmd->pdu;
- hdr->reason = reason;
+ cmd->reject_reason = reason;
cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
if (!cmd->buf_ptr) {
@@ -662,23 +655,16 @@ static int iscsit_add_reject(
cmd->i_state = ISTATE_SEND_REJECT;
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
- ret = wait_for_completion_interruptible(&cmd->reject_comp);
- if (ret != 0)
- return -1;
-
- return (!fail_conn) ? 0 : -1;
+ return -1;
}
-int iscsit_add_reject_from_cmd(
+static int iscsit_add_reject_from_cmd(
+ struct iscsi_cmd *cmd,
u8 reason,
- int fail_conn,
- int add_to_conn,
- unsigned char *buf,
- struct iscsi_cmd *cmd)
+ bool add_to_conn,
+ unsigned char *buf)
{
struct iscsi_conn *conn;
- struct iscsi_reject *hdr;
- int ret;
if (!cmd->conn) {
pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
@@ -688,11 +674,7 @@ int iscsit_add_reject_from_cmd(
conn = cmd->conn;
cmd->iscsi_opcode = ISCSI_OP_REJECT;
- if (fail_conn)
- cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
-
- hdr = (struct iscsi_reject *) cmd->pdu;
- hdr->reason = reason;
+ cmd->reject_reason = reason;
cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
if (!cmd->buf_ptr) {
@@ -709,8 +691,6 @@ int iscsit_add_reject_from_cmd(
cmd->i_state = ISTATE_SEND_REJECT;
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
-
- ret = wait_for_completion_interruptible(&cmd->reject_comp);
/*
* Perform the kref_put now if se_cmd has already been setup by
* scsit_setup_scsi_cmd()
@@ -719,12 +699,19 @@ int iscsit_add_reject_from_cmd(
pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
}
- if (ret != 0)
- return -1;
+ return -1;
+}
- return (!fail_conn) ? 0 : -1;
+static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason,
+ unsigned char *buf)
+{
+ return iscsit_add_reject_from_cmd(cmd, reason, true, buf);
+}
+
+int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf)
+{
+ return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
}
-EXPORT_SYMBOL(iscsit_add_reject_from_cmd);
/*
* Map some portion of the allocated scatterlist to an iovec, suitable for
@@ -844,8 +831,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
" not set. Bad iSCSI Initiator.\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
@@ -865,8 +852,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
" set when Expected Data Transfer Length is 0 for"
" CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
done:
@@ -875,62 +862,62 @@ done:
pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
" MUST be set if Expected Data Transfer Length is not 0."
" Bad iSCSI Initiator\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
(hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
pr_err("Bidirectional operations not supported!\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
pr_err("Illegally set Immediate Bit in iSCSI Initiator"
" Scsi Command PDU.\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
if (payload_length && !conn->sess->sess_ops->ImmediateData) {
pr_err("ImmediateData=No but DataSegmentLength=%u,"
" protocol error.\n", payload_length);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
- if ((be32_to_cpu(hdr->data_length )== payload_length) &&
+ if ((be32_to_cpu(hdr->data_length) == payload_length) &&
(!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
pr_err("Expected Data Transfer Length and Length of"
" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
" bit is not set protocol error\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (payload_length > be32_to_cpu(hdr->data_length)) {
pr_err("DataSegmentLength: %u is greater than"
" EDTL: %u, protocol error.\n", payload_length,
hdr->data_length);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("DataSegmentLength: %u is greater than"
" MaxXmitDataSegmentLength: %u, protocol error.\n",
payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
pr_err("DataSegmentLength: %u is greater than"
" FirstBurstLength: %u, protocol error.\n",
payload_length, conn->sess->sess_ops->FirstBurstLength);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
@@ -985,9 +972,8 @@ done:
dr = iscsit_allocate_datain_req();
if (!dr)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
iscsit_attach_datain_req(cmd, dr);
}
@@ -1015,18 +1001,16 @@ done:
cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
if (cmd->sense_reason) {
if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
goto attach_cmd;
}
if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
attach_cmd:
@@ -1068,17 +1052,13 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* be acknowledged. (See below)
*/
if (!cmd->immediate_data) {
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
- if (!cmd->sense_reason)
- return 0;
-
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ return -1;
+ else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 0;
- } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, (unsigned char *)hdr, cmd);
}
}
@@ -1103,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
*/
if (cmd->sense_reason) {
+ if (cmd->reject_reason)
+ return 0;
+
target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 1;
}
@@ -1111,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* the backend memory allocation.
*/
cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
- if (cmd->sense_reason) {
- target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ if (cmd->sense_reason)
return 1;
- }
return 0;
}
@@ -1124,6 +1105,7 @@ static int
iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
bool dump_payload)
{
+ struct iscsi_conn *conn = cmd->conn;
int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
/*
* Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
@@ -1140,20 +1122,25 @@ after_immediate_data:
* DataCRC, check against ExpCmdSN/MaxCmdSN if
* Immediate Bit is not set.
*/
- cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
+ cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
+ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+ return -1;
+ } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 0;
+ }
if (cmd->sense_reason) {
- if (iscsit_dump_data_payload(cmd->conn,
- cmd->first_burst_len, 1) < 0)
- return -1;
+ int rc;
+
+ rc = iscsit_dump_data_payload(cmd->conn,
+ cmd->first_burst_len, 1);
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return rc;
} else if (cmd->unsolicited_data)
iscsit_set_unsoliticed_dataout(cmd);
- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, (unsigned char *)hdr, cmd);
-
} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
/*
* Immediate Data failed DataCRC and ERL>=1,
@@ -1184,15 +1171,14 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
if (rc < 0)
- return rc;
+ return 0;
/*
* Allocation iovecs needed for struct socket operations for
* traditional iSCSI block I/O.
*/
if (iscsit_allocate_iovecs(cmd) < 0) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 0, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
immed_data = cmd->immediate_data;
@@ -1277,14 +1263,13 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
struct iscsi_data *hdr = (struct iscsi_data *)buf;
struct iscsi_cmd *cmd = NULL;
struct se_cmd *se_cmd;
- unsigned long flags;
u32 payload_length = ntoh24(hdr->dlength);
int rc;
if (!payload_length) {
pr_err("DataOUT payload is ZERO, protocol error.\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buf);
}
/* iSCSI write */
@@ -1301,8 +1286,8 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
pr_err("DataSegmentLength: %u is greater than"
" MaxXmitDataSegmentLength: %u\n", payload_length,
conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buf);
}
cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt,
@@ -1325,8 +1310,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
if (cmd->data_direction != DMA_TO_DEVICE) {
pr_err("Command ITT: 0x%08x received DataOUT for a"
" NON-WRITE command.\n", cmd->init_task_tag);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
se_cmd = &cmd->se_cmd;
iscsit_mod_dataout_timer(cmd);
@@ -1335,8 +1319,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
pr_err("DataOut Offset: %u, Length %u greater than"
" iSCSI Command EDTL %u, protocol error.\n",
hdr->offset, payload_length, cmd->se_cmd.data_length);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
}
if (cmd->unsolicited_data) {
@@ -1356,14 +1339,9 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
*/
/* Something's amiss if we're not in WRITE_PENDING state... */
- spin_lock_irqsave(&se_cmd->t_state_lock, flags);
WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING);
- spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
-
- spin_lock_irqsave(&se_cmd->t_state_lock, flags);
if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE))
dump_unsolicited_data = 1;
- spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
if (dump_unsolicited_data) {
/*
@@ -1528,7 +1506,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
if (rc < 0)
- return rc;
+ return 0;
else if (!cmd)
return 0;
@@ -1541,24 +1519,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
}
-int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
- unsigned char *buf)
+int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_nopout *hdr)
{
- unsigned char *ping_data = NULL;
- int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
- u32 checksum, data_crc, padding = 0, payload_length;
- struct iscsi_cmd *cmd_p = NULL;
- struct kvec *iov = NULL;
- struct iscsi_nopout *hdr;
-
- hdr = (struct iscsi_nopout *) buf;
- payload_length = ntoh24(hdr->dlength);
+ u32 payload_length = ntoh24(hdr->dlength);
if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
" not set, protocol error.\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
}
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
@@ -1566,8 +1536,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
" greater than MaxXmitDataSegmentLength: %u, protocol"
" error.\n", payload_length,
conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
}
pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
@@ -1583,11 +1553,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* can contain ping data.
*/
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
- if (!cmd)
- return iscsit_add_reject(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
-
cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT;
cmd->i_state = ISTATE_SEND_NOPIN;
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
@@ -1599,8 +1564,85 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->data_direction = DMA_NONE;
}
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_nop_out);
+
+int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_nopout *hdr)
+{
+ struct iscsi_cmd *cmd_p = NULL;
+ int cmdsn_ret = 0;
+ /*
+ * Initiator is expecting a NopIN ping reply..
+ */
+ if (hdr->itt != RESERVED_ITT) {
+ BUG_ON(!cmd);
+
+ spin_lock_bh(&conn->cmd_lock);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
+
+ if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+ iscsit_add_cmd_to_response_queue(cmd, conn,
+ cmd->i_state);
+ return 0;
+ }
+
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ return 0;
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ return -1;
+
+ return 0;
+ }
+ /*
+ * This was a response to a unsolicited NOPIN ping.
+ */
+ if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
+ cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
+ if (!cmd_p)
+ return -EINVAL;
+
+ iscsit_stop_nopin_response_timer(conn);
+
+ cmd_p->i_state = ISTATE_REMOVE;
+ iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
+
+ iscsit_start_nopin_timer(conn);
+ return 0;
+ }
+ /*
+ * Otherwise, initiator is not expecting a NOPIN is response.
+ * Just ignore for now.
+ */
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_process_nop_out);
+
+static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
+{
+ unsigned char *ping_data = NULL;
+ struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
+ struct kvec *iov = NULL;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int ret;
+
+ ret = iscsit_setup_nop_out(conn, cmd, hdr);
+ if (ret < 0)
+ return 0;
+ /*
+ * Handle NOP-OUT payload for traditional iSCSI sockets
+ */
if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
- rx_size = payload_length;
+ u32 checksum, data_crc, padding = 0;
+ int niov = 0, rx_got, rx_size = payload_length;
+
ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
if (!ping_data) {
pr_err("Unable to allocate memory for"
@@ -1679,76 +1721,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
pr_debug("Ping Data: \"%s\"\n", ping_data);
}
- if (hdr->itt != RESERVED_ITT) {
- if (!cmd) {
- pr_err("Checking CmdSN for NOPOUT,"
- " but cmd is NULL!\n");
- return -1;
- }
- /*
- * Initiator is expecting a NopIN ping reply,
- */
- spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
- spin_unlock_bh(&conn->cmd_lock);
-
- iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
-
- if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
- iscsit_add_cmd_to_response_queue(cmd, conn,
- cmd->i_state);
- return 0;
- }
-
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
- ret = 0;
- goto ping_out;
- }
- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
-
- return 0;
- }
-
- if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
- /*
- * This was a response to a unsolicited NOPIN ping.
- */
- cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
- if (!cmd_p)
- return -1;
-
- iscsit_stop_nopin_response_timer(conn);
-
- cmd_p->i_state = ISTATE_REMOVE;
- iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
- iscsit_start_nopin_timer(conn);
- } else {
- /*
- * Initiator is not expecting a NOPIN is response.
- * Just ignore for now.
- *
- * iSCSI v19-91 10.18
- * "A NOP-OUT may also be used to confirm a changed
- * ExpStatSN if another PDU will not be available
- * for a long time."
- */
- ret = 0;
- goto out;
- }
-
- return 0;
+ return iscsit_process_nop_out(conn, cmd, hdr);
out:
if (cmd)
iscsit_free_cmd(cmd, false);
-ping_out:
+
kfree(ping_data);
return ret;
}
-EXPORT_SYMBOL(iscsit_handle_nop_out);
int
iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
@@ -1757,8 +1737,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct se_tmr_req *se_tmr;
struct iscsi_tmr_req *tmr_req;
struct iscsi_tm *hdr;
- int out_of_order_cmdsn = 0;
- int ret;
+ int out_of_order_cmdsn = 0, ret;
+ bool sess_ref = false;
u8 function;
hdr = (struct iscsi_tm *) buf;
@@ -1782,8 +1762,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
pr_err("Task Management Request TASK_REASSIGN not"
" issued as immediate command, bad iSCSI Initiator"
"implementation\n");
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
@@ -1795,9 +1775,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (!cmd->tmr_req) {
pr_err("Unable to allocate memory for"
" Task Management command!\n");
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ buf);
}
/*
@@ -1814,6 +1794,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
conn->sess->se_sess, 0, DMA_NONE,
MSG_SIMPLE_TAG, cmd->sense_buffer + 2);
+ target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true);
+ sess_ref = true;
+
switch (function) {
case ISCSI_TM_FUNC_ABORT_TASK:
tcm_function = TMR_ABORT_TASK;
@@ -1839,17 +1822,15 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
default:
pr_err("Unknown iSCSI TMR Function:"
" 0x%02x\n", function);
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
tcm_function, GFP_KERNEL);
if (ret < 0)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 1, buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
}
@@ -1908,9 +1889,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
break;
if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_INVALID, 1, 1,
- buf, cmd);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
break;
default:
pr_err("Unknown TMR function: 0x%02x, protocol"
@@ -1928,15 +1908,13 @@ attach:
spin_unlock_bh(&conn->cmd_lock);
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
- int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+ int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
out_of_order_cmdsn = 1;
else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
return 0;
else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ return -1;
}
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
@@ -1956,51 +1934,135 @@ attach:
* For connection recovery, this is also the default action for
* TMR TASK_REASSIGN.
*/
+ if (sess_ref) {
+ pr_debug("Handle TMR, using sess_ref=true check\n");
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ }
+
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
return 0;
}
EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
/* #warning FIXME: Support Text Command parameters besides SendTargets */
-static int iscsit_handle_text_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int
+iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_text *hdr)
{
- char *text_ptr, *text_in;
- int cmdsn_ret, niov = 0, rx_got, rx_size;
- u32 checksum = 0, data_crc = 0, payload_length;
- u32 padding = 0, pad_bytes = 0, text_length = 0;
- struct iscsi_cmd *cmd;
- struct kvec iov[3];
- struct iscsi_text *hdr;
-
- hdr = (struct iscsi_text *) buf;
- payload_length = ntoh24(hdr->dlength);
+ u32 payload_length = ntoh24(hdr->dlength);
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("Unable to accept text parameter length: %u"
"greater than MaxXmitDataSegmentLength %u.\n",
payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
}
pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
" ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,
hdr->exp_statsn, payload_length);
- rx_size = text_length = payload_length;
- if (text_length) {
- text_in = kzalloc(text_length, GFP_KERNEL);
+ cmd->iscsi_opcode = ISCSI_OP_TEXT;
+ cmd->i_state = ISTATE_SEND_TEXTRSP;
+ cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
+ conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
+ cmd->targ_xfer_tag = 0xFFFFFFFF;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
+ cmd->data_direction = DMA_NONE;
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_text_cmd);
+
+int
+iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_text *hdr)
+{
+ unsigned char *text_in = cmd->text_in_ptr, *text_ptr;
+ int cmdsn_ret;
+
+ if (!text_in) {
+ pr_err("Unable to locate text_in buffer for sendtargets"
+ " discovery\n");
+ goto reject;
+ }
+ if (strncmp("SendTargets", text_in, 11) != 0) {
+ pr_err("Received Text Data that is not"
+ " SendTargets, cannot continue.\n");
+ goto reject;
+ }
+ text_ptr = strchr(text_in, '=');
+ if (!text_ptr) {
+ pr_err("No \"=\" separator found in Text Data,"
+ " cannot continue.\n");
+ goto reject;
+ }
+ if (!strncmp("=All", text_ptr, 4)) {
+ cmd->cmd_flags |= IFC_SENDTARGETS_ALL;
+ } else if (!strncmp("=iqn.", text_ptr, 5) ||
+ !strncmp("=eui.", text_ptr, 5)) {
+ cmd->cmd_flags |= IFC_SENDTARGETS_SINGLE;
+ } else {
+ pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr);
+ goto reject;
+ }
+
+ spin_lock_bh(&conn->cmd_lock);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
+
+ if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ return -1;
+
+ return 0;
+ }
+
+ return iscsit_execute_cmd(cmd, 0);
+
+reject:
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
+}
+EXPORT_SYMBOL(iscsit_process_text_cmd);
+
+static int
+iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
+{
+ struct iscsi_text *hdr = (struct iscsi_text *)buf;
+ char *text_in = NULL;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int rx_size, rc;
+
+ rc = iscsit_setup_text_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return 0;
+
+ rx_size = payload_length;
+ if (payload_length) {
+ u32 checksum = 0, data_crc = 0;
+ u32 padding = 0, pad_bytes = 0;
+ int niov = 0, rx_got;
+ struct kvec iov[3];
+
+ text_in = kzalloc(payload_length, GFP_KERNEL);
if (!text_in) {
pr_err("Unable to allocate memory for"
" incoming text parameters\n");
- return -1;
+ goto reject;
}
+ cmd->text_in_ptr = text_in;
memset(iov, 0, 3 * sizeof(struct kvec));
iov[niov].iov_base = text_in;
- iov[niov++].iov_len = text_length;
+ iov[niov++].iov_len = payload_length;
padding = ((-payload_length) & 3);
if (padding != 0) {
@@ -2017,14 +2079,12 @@ static int iscsit_handle_text_cmd(
}
rx_got = rx_data(conn, &iov[0], niov, rx_size);
- if (rx_got != rx_size) {
- kfree(text_in);
- return -1;
- }
+ if (rx_got != rx_size)
+ goto reject;
if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
- text_in, text_length,
+ text_in, payload_length,
padding, (u8 *)&pad_bytes,
(u8 *)&data_crc);
@@ -2036,8 +2096,7 @@ static int iscsit_handle_text_cmd(
pr_err("Unable to recover from"
" Text Data digest failure while in"
" ERL=0.\n");
- kfree(text_in);
- return -1;
+ goto reject;
} else {
/*
* Silently drop this PDU and let the
@@ -2052,68 +2111,22 @@ static int iscsit_handle_text_cmd(
} else {
pr_debug("Got CRC32C DataDigest"
" 0x%08x for %u bytes of text data.\n",
- checksum, text_length);
+ checksum, payload_length);
}
}
- text_in[text_length - 1] = '\0';
+ text_in[payload_length - 1] = '\0';
pr_debug("Successfully read %d bytes of text"
- " data.\n", text_length);
-
- if (strncmp("SendTargets", text_in, 11) != 0) {
- pr_err("Received Text Data that is not"
- " SendTargets, cannot continue.\n");
- kfree(text_in);
- return -1;
- }
- text_ptr = strchr(text_in, '=');
- if (!text_ptr) {
- pr_err("No \"=\" separator found in Text Data,"
- " cannot continue.\n");
- kfree(text_in);
- return -1;
- }
- if (strncmp("=All", text_ptr, 4) != 0) {
- pr_err("Unable to locate All value for"
- " SendTargets key, cannot continue.\n");
- kfree(text_in);
- return -1;
- }
-/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */
- kfree(text_in);
+ " data.\n", payload_length);
}
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
-
- cmd->iscsi_opcode = ISCSI_OP_TEXT;
- cmd->i_state = ISTATE_SEND_TEXTRSP;
- cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
- conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
- cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
- cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
- cmd->data_direction = DMA_NONE;
-
- spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
- spin_unlock_bh(&conn->cmd_lock);
+ return iscsit_process_text_cmd(conn, cmd, hdr);
- iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
-
- if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
-
- return 0;
- }
-
- return iscsit_execute_cmd(cmd, 0);
+reject:
+ kfree(cmd->text_in_ptr);
+ cmd->text_in_ptr = NULL;
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
+EXPORT_SYMBOL(iscsit_handle_text_cmd);
int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
@@ -2292,14 +2305,11 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (ret < 0)
return ret;
} else {
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
logout_remove = 0;
- } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
- }
+ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ return -1;
}
return logout_remove;
@@ -2323,8 +2333,8 @@ static int iscsit_handle_snack(
if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
pr_err("Initiator sent SNACK request while in"
" ErrorRecoveryLevel=0.\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buf);
}
/*
* SNACK_DATA and SNACK_R2T are both 0, so check which function to
@@ -2348,13 +2358,13 @@ static int iscsit_handle_snack(
case ISCSI_FLAG_SNACK_TYPE_RDATA:
/* FIXME: Support R-Data SNACK */
pr_err("R-Data SNACK Not Supported.\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buf);
default:
pr_err("Unknown SNACK type 0x%02x, protocol"
" error.\n", hdr->flags & 0x0f);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buf);
}
return 0;
@@ -2426,14 +2436,14 @@ static int iscsit_handle_immediate_data(
pr_err("Unable to recover from"
" Immediate Data digest failure while"
" in ERL=0.\n");
- iscsit_add_reject_from_cmd(
+ iscsit_reject_cmd(cmd,
ISCSI_REASON_DATA_DIGEST_ERROR,
- 1, 0, (unsigned char *)hdr, cmd);
+ (unsigned char *)hdr);
return IMMEDIATE_DATA_CANNOT_RECOVER;
} else {
- iscsit_add_reject_from_cmd(
+ iscsit_reject_cmd(cmd,
ISCSI_REASON_DATA_DIGEST_ERROR,
- 0, 0, (unsigned char *)hdr, cmd);
+ (unsigned char *)hdr);
return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
}
} else {
@@ -3276,8 +3286,6 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
return ISCSI_TMF_RSP_NO_LUN;
case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
return ISCSI_TMF_RSP_NOT_SUPPORTED;
- case TMR_FUNCTION_AUTHORIZATION_FAILED:
- return ISCSI_TMF_RSP_AUTH_FAILED;
case TMR_FUNCTION_REJECTED:
default:
return ISCSI_TMF_RSP_REJECTED;
@@ -3372,6 +3380,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
struct iscsi_tpg_np *tpg_np;
int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;
unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
+ unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,
SENDTARGETS_BUF_LIMIT);
@@ -3382,9 +3391,31 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
" response.\n");
return -ENOMEM;
}
+ /*
+ * Locate pointer to iqn./eui. string for IFC_SENDTARGETS_SINGLE
+ * explicit case..
+ */
+ if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) {
+ text_ptr = strchr(text_in, '=');
+ if (!text_ptr) {
+ pr_err("Unable to locate '=' string in text_in:"
+ " %s\n", text_in);
+ kfree(payload);
+ return -EINVAL;
+ }
+ /*
+ * Skip over '=' character..
+ */
+ text_ptr += 1;
+ }
spin_lock(&tiqn_lock);
list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
+ if ((cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) &&
+ strcmp(tiqn->tiqn, text_ptr)) {
+ continue;
+ }
+
len = sprintf(buf, "TargetName=%s", tiqn->tiqn);
len += 1;
@@ -3438,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
eob:
if (end_of_buf)
break;
+
+ if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE)
+ break;
}
spin_unlock(&tiqn_lock);
@@ -3446,52 +3480,62 @@ eob:
return payload_len;
}
-/*
- * FIXME: Add support for F_BIT and C_BIT when the length is longer than
- * MaxRecvDataSegmentLength.
- */
-static int iscsit_send_text_rsp(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+int
+iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_text_rsp *hdr)
{
- struct iscsi_text_rsp *hdr;
- struct kvec *iov;
- u32 padding = 0, tx_size = 0;
- int text_length, iov_count = 0;
+ int text_length, padding;
text_length = iscsit_build_sendtargets_response(cmd);
if (text_length < 0)
return text_length;
+ hdr->opcode = ISCSI_OP_TEXT_RSP;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
padding = ((-text_length) & 3);
- if (padding != 0) {
- memset(cmd->buf_ptr + text_length, 0, padding);
- pr_debug("Attaching %u additional bytes for"
- " padding.\n", padding);
- }
-
- hdr = (struct iscsi_text_rsp *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_TEXT_RSP;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hton24(hdr->dlength, text_length);
- hdr->itt = cmd->init_task_tag;
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- cmd->stat_sn = conn->stat_sn++;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ hdr->itt = cmd->init_task_tag;
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ cmd->stat_sn = conn->stat_sn++;
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
iscsit_increment_maxcmdsn(cmd, conn->sess);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
- iov = &cmd->iov_misc[0];
+ pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
+ " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
+ text_length, conn->cid);
+
+ return text_length + padding;
+}
+EXPORT_SYMBOL(iscsit_build_text_rsp);
+/*
+ * FIXME: Add support for F_BIT and C_BIT when the length is longer than
+ * MaxRecvDataSegmentLength.
+ */
+static int iscsit_send_text_rsp(
+ struct iscsi_cmd *cmd,
+ struct iscsi_conn *conn)
+{
+ struct iscsi_text_rsp *hdr = (struct iscsi_text_rsp *)cmd->pdu;
+ struct kvec *iov;
+ u32 tx_size = 0;
+ int text_length, iov_count = 0, rc;
+
+ rc = iscsit_build_text_rsp(cmd, conn, hdr);
+ if (rc < 0)
+ return rc;
+
+ text_length = rc;
+ iov = &cmd->iov_misc[0];
iov[iov_count].iov_base = cmd->pdu;
iov[iov_count++].iov_len = ISCSI_HDR_LEN;
iov[iov_count].iov_base = cmd->buf_ptr;
- iov[iov_count++].iov_len = text_length + padding;
+ iov[iov_count++].iov_len = text_length;
- tx_size += (ISCSI_HDR_LEN + text_length + padding);
+ tx_size += (ISCSI_HDR_LEN + text_length);
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
@@ -3507,7 +3551,7 @@ static int iscsit_send_text_rsp(
if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- cmd->buf_ptr, (text_length + padding),
+ cmd->buf_ptr, text_length,
0, NULL, (u8 *)&cmd->data_crc);
iov[iov_count].iov_base = &cmd->data_crc;
@@ -3515,16 +3559,13 @@ static int iscsit_send_text_rsp(
tx_size += ISCSI_CRC_LEN;
pr_debug("Attaching DataDigest for %u bytes of text"
- " data, CRC 0x%08x\n", (text_length + padding),
+ " data, CRC 0x%08x\n", text_length,
cmd->data_crc);
}
cmd->iov_misc_count = iov_count;
cmd->tx_size = tx_size;
- pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
- " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
- text_length, conn->cid);
return 0;
}
@@ -3533,6 +3574,7 @@ iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
struct iscsi_reject *hdr)
{
hdr->opcode = ISCSI_OP_REJECT;
+ hdr->reason = cmd->reject_reason;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hton24(hdr->dlength, ISCSI_HDR_LEN);
hdr->ffffffff = cpu_to_be32(0xffffffff);
@@ -3806,18 +3848,11 @@ check_rsp_state:
case ISTATE_SEND_STATUS_RECOVERY:
case ISTATE_SEND_TEXTRSP:
case ISTATE_SEND_TASKMGTRSP:
+ case ISTATE_SEND_REJECT:
spin_lock_bh(&cmd->istate_lock);
cmd->i_state = ISTATE_SENT_STATUS;
spin_unlock_bh(&cmd->istate_lock);
break;
- case ISTATE_SEND_REJECT:
- if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
- cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
- complete(&cmd->reject_comp);
- goto err;
- }
- complete(&cmd->reject_comp);
- break;
default:
pr_err("Unknown Opcode: 0x%02x ITT:"
" 0x%08x, i_state: %d on CID: %hu\n",
@@ -3922,8 +3957,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
case ISCSI_OP_SCSI_CMD:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
+ goto reject;
ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
break;
@@ -3935,27 +3969,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
+ goto reject;
}
ret = iscsit_handle_nop_out(conn, cmd, buf);
break;
case ISCSI_OP_SCSI_TMFUNC:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
+ goto reject;
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break;
case ISCSI_OP_TEXT:
- ret = iscsit_handle_text_cmd(conn, buf);
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ goto reject;
+
+ ret = iscsit_handle_text_cmd(conn, cmd, buf);
break;
case ISCSI_OP_LOGOUT:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
+ goto reject;
ret = iscsit_handle_logout_cmd(conn, cmd, buf);
if (ret > 0)
@@ -3987,6 +4022,8 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
}
return ret;
+reject:
+ return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
int iscsi_target_rx_thread(void *arg)
@@ -4039,11 +4076,6 @@ restart:
goto transport_err;
}
- /*
- * Set conn->bad_hdr for use with REJECT PDUs.
- */
- memcpy(&conn->bad_hdr, &buffer, ISCSI_HDR_LEN);
-
if (conn->conn_ops->HeaderDigest) {
iov.iov_base = &digest;
iov.iov_len = ISCSI_CRC_LEN;
@@ -4086,8 +4118,8 @@ restart:
(!(opcode & ISCSI_OP_LOGOUT)))) {
pr_err("Received illegal iSCSI Opcode: 0x%02x"
" while in Discovery Session, rejecting.\n", opcode);
- iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buffer, conn);
+ iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ buffer);
goto transport_err;
}
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index a0050b2f294e..2c437cb8ca00 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -15,7 +15,7 @@ extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
struct iscsi_portal_group *);
extern int iscsit_del_np(struct iscsi_np *);
-extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
+extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 8d8b3ff68490..bbfd28893164 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -20,6 +20,7 @@
****************************************************************************/
#include <linux/configfs.h>
+#include <linux/ctype.h>
#include <linux/export.h>
#include <linux/inet.h>
#include <target/target_core_base.h>
@@ -78,11 +79,12 @@ static ssize_t lio_target_np_store_sctp(
struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
struct iscsi_tpg_np, se_tpg_np);
struct iscsi_tpg_np *tpg_np_sctp = NULL;
- char *endptr;
u32 op;
int ret;
- op = simple_strtoul(page, &endptr, 0);
+ ret = kstrtou32(page, 0, &op);
+ if (ret)
+ return ret;
if ((op != 1) && (op != 0)) {
pr_err("Illegal value for tpg_enable: %u\n", op);
return -EINVAL;
@@ -382,11 +384,12 @@ static ssize_t iscsi_nacl_attrib_store_##name( \
{ \
struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
se_node_acl); \
- char *endptr; \
u32 val; \
int ret; \
\
- val = simple_strtoul(page, &endptr, 0); \
+ ret = kstrtou32(page, 0, &val); \
+ if (ret) \
+ return ret; \
ret = iscsit_na_##name(nacl, val); \
if (ret < 0) \
return ret; \
@@ -474,7 +477,7 @@ static ssize_t __iscsi_##prefix##_store_##name( \
if (!capable(CAP_SYS_ADMIN)) \
return -EPERM; \
\
- snprintf(auth->name, PAGE_SIZE, "%s", page); \
+ snprintf(auth->name, sizeof(auth->name), "%s", page); \
if (!strncmp("NULL", auth->name, 4)) \
auth->naf_flags &= ~flags; \
else \
@@ -789,11 +792,12 @@ static ssize_t lio_target_nacl_store_cmdsn_depth(
struct iscsi_portal_group *tpg = container_of(se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
struct config_item *acl_ci, *tpg_ci, *wwn_ci;
- char *endptr;
u32 cmdsn_depth = 0;
int ret;
- cmdsn_depth = simple_strtoul(page, &endptr, 0);
+ ret = kstrtou32(page, 0, &cmdsn_depth);
+ if (ret)
+ return ret;
if (cmdsn_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) {
pr_err("Passed cmdsn_depth: %u exceeds"
" TA_DEFAULT_CMDSN_DEPTH_MAX: %u\n", cmdsn_depth,
@@ -977,14 +981,15 @@ static ssize_t iscsi_tpg_attrib_store_##name( \
{ \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
- char *endptr; \
u32 val; \
int ret; \
\
if (iscsit_get_tpg(tpg) < 0) \
return -EINVAL; \
\
- val = simple_strtoul(page, &endptr, 0); \
+ ret = kstrtou32(page, 0, &val); \
+ if (ret) \
+ goto out; \
ret = iscsit_ta_##name(tpg, val); \
if (ret < 0) \
goto out; \
@@ -1053,6 +1058,131 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
/* End items for lio_target_tpg_attrib_cit */
+/* Start items for lio_target_tpg_auth_cit */
+
+#define __DEF_TPG_AUTH_STR(prefix, name, flags) \
+static ssize_t __iscsi_##prefix##_show_##name( \
+ struct se_portal_group *se_tpg, \
+ char *page) \
+{ \
+ struct iscsi_portal_group *tpg = container_of(se_tpg, \
+ struct iscsi_portal_group, tpg_se_tpg); \
+ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \
+ \
+ if (!capable(CAP_SYS_ADMIN)) \
+ return -EPERM; \
+ \
+ return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \
+} \
+ \
+static ssize_t __iscsi_##prefix##_store_##name( \
+ struct se_portal_group *se_tpg, \
+ const char *page, \
+ size_t count) \
+{ \
+ struct iscsi_portal_group *tpg = container_of(se_tpg, \
+ struct iscsi_portal_group, tpg_se_tpg); \
+ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \
+ \
+ if (!capable(CAP_SYS_ADMIN)) \
+ return -EPERM; \
+ \
+ snprintf(auth->name, sizeof(auth->name), "%s", page); \
+ if (!(strncmp("NULL", auth->name, 4))) \
+ auth->naf_flags &= ~flags; \
+ else \
+ auth->naf_flags |= flags; \
+ \
+ if ((auth->naf_flags & NAF_USERID_IN_SET) && \
+ (auth->naf_flags & NAF_PASSWORD_IN_SET)) \
+ auth->authenticate_target = 1; \
+ else \
+ auth->authenticate_target = 0; \
+ \
+ return count; \
+}
+
+#define __DEF_TPG_AUTH_INT(prefix, name) \
+static ssize_t __iscsi_##prefix##_show_##name( \
+ struct se_portal_group *se_tpg, \
+ char *page) \
+{ \
+ struct iscsi_portal_group *tpg = container_of(se_tpg, \
+ struct iscsi_portal_group, tpg_se_tpg); \
+ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \
+ \
+ if (!capable(CAP_SYS_ADMIN)) \
+ return -EPERM; \
+ \
+ return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \
+}
+
+#define DEF_TPG_AUTH_STR(name, flags) \
+ __DEF_TPG_AUTH_STR(tpg_auth, name, flags) \
+static ssize_t iscsi_tpg_auth_show_##name( \
+ struct se_portal_group *se_tpg, \
+ char *page) \
+{ \
+ return __iscsi_tpg_auth_show_##name(se_tpg, page); \
+} \
+ \
+static ssize_t iscsi_tpg_auth_store_##name( \
+ struct se_portal_group *se_tpg, \
+ const char *page, \
+ size_t count) \
+{ \
+ return __iscsi_tpg_auth_store_##name(se_tpg, page, count); \
+}
+
+#define DEF_TPG_AUTH_INT(name) \
+ __DEF_TPG_AUTH_INT(tpg_auth, name) \
+static ssize_t iscsi_tpg_auth_show_##name( \
+ struct se_portal_group *se_tpg, \
+ char *page) \
+{ \
+ return __iscsi_tpg_auth_show_##name(se_tpg, page); \
+}
+
+#define TPG_AUTH_ATTR(_name, _mode) TF_TPG_AUTH_ATTR(iscsi, _name, _mode);
+#define TPG_AUTH_ATTR_RO(_name) TF_TPG_AUTH_ATTR_RO(iscsi, _name);
+
+/*
+ * * One-way authentication userid
+ * */
+DEF_TPG_AUTH_STR(userid, NAF_USERID_SET);
+TPG_AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
+/*
+ * * One-way authentication password
+ * */
+DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET);
+TPG_AUTH_ATTR(password, S_IRUGO | S_IWUSR);
+/*
+ * * Enforce mutual authentication
+ * */
+DEF_TPG_AUTH_INT(authenticate_target);
+TPG_AUTH_ATTR_RO(authenticate_target);
+/*
+ * * Mutual authentication userid
+ * */
+DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+TPG_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
+/*
+ * * Mutual authentication password
+ * */
+DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+TPG_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_tpg_auth_attrs[] = {
+ &iscsi_tpg_auth_userid.attr,
+ &iscsi_tpg_auth_password.attr,
+ &iscsi_tpg_auth_authenticate_target.attr,
+ &iscsi_tpg_auth_userid_mutual.attr,
+ &iscsi_tpg_auth_password_mutual.attr,
+ NULL,
+};
+
+/* End items for lio_target_tpg_auth_cit */
+
/* Start items for lio_target_tpg_param_cit */
#define DEF_TPG_PARAM(name) \
@@ -1087,13 +1217,14 @@ static ssize_t iscsi_tpg_param_store_##name( \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
char *buf; \
- int ret; \
+ int ret, len; \
\
buf = kzalloc(PAGE_SIZE, GFP_KERNEL); \
if (!buf) \
return -ENOMEM; \
- snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page); \
- buf[strlen(buf)-1] = '\0'; /* Kill newline */ \
+ len = snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page); \
+ if (isspace(buf[len-1])) \
+ buf[len-1] = '\0'; /* Kill newline */ \
\
if (iscsit_get_tpg(tpg) < 0) { \
kfree(buf); \
@@ -1230,11 +1361,12 @@ static ssize_t lio_target_tpg_store_enable(
{
struct iscsi_portal_group *tpg = container_of(se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
- char *endptr;
u32 op;
- int ret = 0;
+ int ret;
- op = simple_strtoul(page, &endptr, 0);
+ ret = kstrtou32(page, 0, &op);
+ if (ret)
+ return ret;
if ((op != 1) && (op != 0)) {
pr_err("Illegal value for tpg_enable: %u\n", op);
return -EINVAL;
@@ -1282,15 +1414,15 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
{
struct iscsi_portal_group *tpg;
struct iscsi_tiqn *tiqn;
- char *tpgt_str, *end_ptr;
- int ret = 0;
- unsigned short int tpgt;
+ char *tpgt_str;
+ int ret;
+ u16 tpgt;
tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
/*
* Only tpgt_# directory groups can be created below
* target/iscsi/iqn.superturodiskarry/
- */
+ */
tpgt_str = strstr(name, "tpgt_");
if (!tpgt_str) {
pr_err("Unable to locate \"tpgt_#\" directory"
@@ -1298,7 +1430,9 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
return NULL;
}
tpgt_str += 5; /* Skip ahead of "tpgt_" */
- tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
+ ret = kstrtou16(tpgt_str, 0, &tpgt);
+ if (ret)
+ return NULL;
tpg = iscsit_alloc_portal_group(tiqn, tpgt);
if (!tpg)
@@ -1506,10 +1640,12 @@ static ssize_t iscsi_disc_store_enforce_discovery_auth(
{
struct iscsi_param *param;
struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg;
- char *endptr;
u32 op;
+ int err;
- op = simple_strtoul(page, &endptr, 0);
+ err = kstrtou32(page, 0, &op);
+ if (err)
+ return -EINVAL;
if ((op != 1) && (op != 0)) {
pr_err("Illegal value for enforce_discovery_auth:"
" %u\n", op);
@@ -1655,13 +1791,12 @@ static int lio_queue_status(struct se_cmd *se_cmd)
return 0;
}
-static int lio_queue_tm_rsp(struct se_cmd *se_cmd)
+static void lio_queue_tm_rsp(struct se_cmd *se_cmd)
{
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
cmd->i_state = ISTATE_SEND_TASKMGTRSP;
iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
- return 0;
}
static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg)
@@ -1866,6 +2001,7 @@ int iscsi_target_register_configfs(void)
TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;
TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 60ec4b92be03..4f77a78edef9 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -132,7 +132,8 @@ enum cmd_flags_table {
ICF_CONTIG_MEMORY = 0x00000020,
ICF_ATTACHED_TO_RQUEUE = 0x00000040,
ICF_OOO_CMDSN = 0x00000080,
- ICF_REJECT_FAIL_CONN = 0x00000100,
+ IFC_SENDTARGETS_ALL = 0x00000100,
+ IFC_SENDTARGETS_SINGLE = 0x00000200,
};
/* struct iscsi_cmd->i_state */
@@ -366,6 +367,8 @@ struct iscsi_cmd {
u8 maxcmdsn_inc;
/* Immediate Unsolicited Dataout */
u8 unsolicited_data;
+ /* Reject reason code */
+ u8 reject_reason;
/* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
u16 logout_cid;
/* Command flags */
@@ -427,6 +430,8 @@ struct iscsi_cmd {
u32 tx_size;
/* Buffer used for various purposes */
void *buf_ptr;
+ /* Used by SendTargets=[iqn.,eui.] discovery */
+ void *text_in_ptr;
/* See include/linux/dma-mapping.h */
enum dma_data_direction data_direction;
/* iSCSI PDU Header + CRC */
@@ -446,7 +451,6 @@ struct iscsi_cmd {
struct list_head datain_list;
/* R2T List */
struct list_head cmd_r2t_list;
- struct completion reject_comp;
/* Timer for DataOUT */
struct timer_list dataout_timer;
/* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
@@ -528,8 +532,6 @@ struct iscsi_conn {
u32 of_marker;
/* Used for calculating OFMarker offset to next PDU */
u32 of_marker_offset;
- /* Complete Bad PDU for sending reject */
- unsigned char bad_hdr[ISCSI_HDR_LEN];
#define IPV6_ADDRESS_SPACE 48
unsigned char login_ip[IPV6_ADDRESS_SPACE];
unsigned char local_ip[IPV6_ADDRESS_SPACE];
@@ -809,6 +811,7 @@ struct iscsi_portal_group {
struct mutex tpg_access_lock;
struct mutex np_login_lock;
struct iscsi_tpg_attrib tpg_attrib;
+ struct iscsi_node_auth tpg_demo_auth;
/* Pointer to default list of iSCSI parameters for TPG */
struct iscsi_param_list *param_list;
struct iscsi_tiqn *tpg_tiqn;
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index dcb199da06b9..08bd87833321 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -746,13 +746,12 @@ int iscsit_check_post_dataout(
if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
pr_err("Unable to recover from DataOUT CRC"
" failure while ERL=0, closing session.\n");
- iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
- 1, 0, buf, cmd);
+ iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
+ buf);
return DATAOUT_CANNOT_RECOVER;
}
- iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
- 0, 0, buf, cmd);
+ iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);
return iscsit_dataout_post_crc_failed(cmd, buf);
}
}
@@ -909,6 +908,7 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
wait_for_completion(&conn->conn_wait_comp);
complete(&conn->conn_post_wait_comp);
}
+EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);
void iscsit_fall_back_to_erl0(struct iscsi_session *sess)
{
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 40d9dbca987b..586c268679a4 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -162,9 +162,8 @@ static int iscsit_handle_r2t_snack(
" protocol error.\n", cmd->init_task_tag, begrun,
(begrun + runlength), cmd->acked_data_sn);
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (runlength) {
@@ -173,8 +172,8 @@ static int iscsit_handle_r2t_snack(
" with BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
" current R2TSN: 0x%08x, protocol error.\n",
cmd->init_task_tag, begrun, runlength, cmd->r2t_sn);
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_INVALID, buf);
}
last_r2tsn = (begrun + runlength);
} else
@@ -433,8 +432,7 @@ static int iscsit_handle_recovery_datain(
" protocol error.\n", cmd->init_task_tag, begrun,
(begrun + runlength), cmd->acked_data_sn);
- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
/*
@@ -445,14 +443,14 @@ static int iscsit_handle_recovery_datain(
pr_err("Initiator requesting BegRun: 0x%08x, RunLength"
": 0x%08x greater than maximum DataSN: 0x%08x.\n",
begrun, runlength, (cmd->data_sn - 1));
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID,
+ buf);
}
dr = iscsit_allocate_datain_req();
if (!dr)
- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 0, buf, cmd);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ buf);
dr->data_sn = dr->begrun = begrun;
dr->runlength = runlength;
@@ -1090,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(
ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
if (!ooo_cmdsn)
- return CMDSN_ERROR_CANNOT_RECOVER;
+ return -ENOMEM;
ooo_cmdsn->cmd = cmd;
ooo_cmdsn->batch_count = (batch) ?
@@ -1101,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(
if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
- return CMDSN_ERROR_CANNOT_RECOVER;
+ return -ENOMEM;
}
- return CMDSN_HIGHER_THAN_EXP;
+ return 0;
}
static int iscsit_set_dataout_timeout_values(
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index cd5018ff9cd7..c4675b4ceb49 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -112,6 +112,7 @@ static u32 iscsi_handle_authentication(
struct iscsi_session *sess = conn->sess;
struct iscsi_node_auth *auth;
struct iscsi_node_acl *iscsi_nacl;
+ struct iscsi_portal_group *iscsi_tpg;
struct se_node_acl *se_nacl;
if (!sess->sess_ops->SessionType) {
@@ -132,7 +133,17 @@ static u32 iscsi_handle_authentication(
return -1;
}
- auth = ISCSI_NODE_AUTH(iscsi_nacl);
+ if (se_nacl->dynamic_node_acl) {
+ iscsi_tpg = container_of(se_nacl->se_tpg,
+ struct iscsi_portal_group, tpg_se_tpg);
+
+ auth = &iscsi_tpg->tpg_demo_auth;
+ } else {
+ iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
+ se_node_acl);
+
+ auth = ISCSI_NODE_AUTH(iscsi_nacl);
+ }
} else {
/*
* For SessionType=Discovery
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index e38222191a33..35fd6439eb01 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -1799,9 +1799,6 @@ void iscsi_set_connection_parameters(
* this key is not sent over the wire.
*/
if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
- if (param_list->iser == true)
- continue;
-
ops->MaxXmitDataSegmentLength =
simple_strtoul(param->value, &tmpptr, 0);
pr_debug("MaxXmitDataSegmentLength: %s\n",
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 08a3bacef0c5..1df06d5e4e01 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -178,7 +178,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
INIT_LIST_HEAD(&cmd->i_conn_node);
INIT_LIST_HEAD(&cmd->datain_list);
INIT_LIST_HEAD(&cmd->cmd_r2t_list);
- init_completion(&cmd->reject_comp);
spin_lock_init(&cmd->datain_lock);
spin_lock_init(&cmd->dataout_timeout_lock);
spin_lock_init(&cmd->istate_lock);
@@ -284,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
* Commands may be received out of order if MC/S is in use.
* Ensure they are executed in CmdSN order.
*/
-int iscsit_sequence_cmd(
- struct iscsi_conn *conn,
- struct iscsi_cmd *cmd,
- __be32 cmdsn)
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf, __be32 cmdsn)
{
- int ret;
- int cmdsn_ret;
+ int ret, cmdsn_ret;
+ bool reject = false;
+ u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
mutex_lock(&conn->sess->cmdsn_mutex);
@@ -300,9 +298,19 @@ int iscsit_sequence_cmd(
ret = iscsit_execute_cmd(cmd, 0);
if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
iscsit_execute_ooo_cmdsns(conn->sess);
+ else if (ret < 0) {
+ reject = true;
+ ret = CMDSN_ERROR_CANNOT_RECOVER;
+ }
break;
case CMDSN_HIGHER_THAN_EXP:
ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
+ if (ret < 0) {
+ reject = true;
+ ret = CMDSN_ERROR_CANNOT_RECOVER;
+ break;
+ }
+ ret = CMDSN_HIGHER_THAN_EXP;
break;
case CMDSN_LOWER_THAN_EXP:
cmd->i_state = ISTATE_REMOVE;
@@ -310,11 +318,16 @@ int iscsit_sequence_cmd(
ret = cmdsn_ret;
break;
default:
+ reason = ISCSI_REASON_PROTOCOL_ERROR;
+ reject = true;
ret = cmdsn_ret;
break;
}
mutex_unlock(&conn->sess->cmdsn_mutex);
+ if (reject)
+ iscsit_reject_cmd(cmd, reason, buf);
+
return ret;
}
EXPORT_SYMBOL(iscsit_sequence_cmd);
@@ -681,6 +694,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
kfree(cmd->seq_list);
kfree(cmd->tmr_req);
kfree(cmd->iov_data);
+ kfree(cmd->text_in_ptr);
kmem_cache_free(lio_cmd_cache, cmd);
}
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index a4422659d049..e4fc34a02f57 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn);
+extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char * ,__be32 cmdsn);
extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 7c908141cc8a..568ad25f25d3 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -786,7 +786,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
return 0;
}
-static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
{
struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr;
@@ -796,7 +796,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
*/
atomic_set(&tl_tmr->tmr_complete, 1);
wake_up(&tl_tmr->tl_tmr_wait);
- return 0;
}
static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index d3536f57444f..e51b09a04d52 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -1842,9 +1842,8 @@ static int sbp_queue_status(struct se_cmd *se_cmd)
return sbp_send_sense(req);
}
-static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+static void sbp_queue_tm_rsp(struct se_cmd *se_cmd)
{
- return 0;
}
static int sbp_check_stop_free(struct se_cmd *se_cmd)
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 4a8bd36d3958..e4d22933efaf 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -983,7 +983,6 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,
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);
@@ -992,12 +991,11 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,
return sprintf(page, "No SPC-3 Reservation holder\n");
se_nacl = pr_reg->pr_reg_nacl;
- prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
- PR_REG_ISID_ID_LEN);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
return sprintf(page, "SPC-3 Reservation: %s Initiator: %s%s\n",
se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(),
- se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+ se_nacl->initiatorname, i_buf);
}
static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev,
@@ -1116,7 +1114,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
unsigned char buf[384];
char i_buf[PR_REG_ISID_ID_LEN];
ssize_t len = 0;
- int reg_count = 0, prf_isid;
+ int reg_count = 0;
len += sprintf(page+len, "SPC-3 PR Registrations:\n");
@@ -1127,12 +1125,11 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
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],
+ core_pr_dump_initiator_port(pr_reg, i_buf,
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_reg_nacl->initiatorname, i_buf, pr_reg->pr_res_key,
pr_reg->pr_res_generation);
if (len + strlen(buf) >= PAGE_SIZE)
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 4630481b6043..8f4142fe5f19 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -1410,7 +1410,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);
spin_lock_init(&dev->t10_alua.tg_pt_gps_lock);
- dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
dev->t10_wwn.t10_dev = dev;
dev->t10_alua.t10_dev = dev;
@@ -1545,7 +1544,7 @@ int core_dev_setup_virtual_lun0(void)
{
struct se_hba *hba;
struct se_device *dev;
- char buf[16];
+ char buf[] = "rd_pages=8,rd_nullio=1";
int ret;
hba = core_alloc_hba("rd_mcp", 0, HBA_FLAGS_INTERNAL_USE);
@@ -1558,8 +1557,6 @@ int core_dev_setup_virtual_lun0(void)
goto out_free_hba;
}
- memset(buf, 0, 16);
- sprintf(buf, "rd_pages=8");
hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf));
ret = target_configure_device(dev);
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 04c775cb3e65..eb56eb129563 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -965,6 +965,19 @@ TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
/* End of tfc_tpg_attrib_cit */
+/* Start of tfc_tpg_auth_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_auth, se_portal_group, tpg_auth_group);
+
+static struct configfs_item_operations target_fabric_tpg_auth_item_ops = {
+ .show_attribute = target_fabric_tpg_auth_attr_show,
+ .store_attribute = target_fabric_tpg_auth_attr_store,
+};
+
+TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_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);
@@ -1030,8 +1043,9 @@ static struct config_group *target_fabric_make_tpg(
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;
+ se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
+ se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
+ se_tpg->tpg_group.default_groups[6] = NULL;
config_group_init_type_name(&se_tpg->tpg_group, name,
&TF_CIT_TMPL(tf)->tfc_tpg_base_cit);
@@ -1043,6 +1057,8 @@ static struct config_group *target_fabric_make_tpg(
&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_auth_group, "auth",
+ &TF_CIT_TMPL(tf)->tfc_tpg_auth_cit);
config_group_init_type_name(&se_tpg->tpg_param_group, "param",
&TF_CIT_TMPL(tf)->tfc_tpg_param_cit);
@@ -1202,6 +1218,7 @@ int target_fabric_setup_cits(struct target_fabric_configfs *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_auth_cit(tf);
target_fabric_setup_tpg_param_cit(tf);
target_fabric_setup_tpg_nacl_cit(tf);
target_fabric_setup_tpg_nacl_base_cit(tf);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 3240f2cc81ef..bd78faf67c6b 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -53,18 +53,28 @@ struct pr_transport_id_holder {
struct list_head dest_list;
};
-int core_pr_dump_initiator_port(
+void core_pr_dump_initiator_port(
struct t10_pr_registration *pr_reg,
char *buf,
u32 size)
{
if (!pr_reg->isid_present_at_reg)
- return 0;
+ buf[0] = '\0';
- snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]);
- return 1;
+ snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid);
}
+enum register_type {
+ REGISTER,
+ REGISTER_AND_IGNORE_EXISTING_KEY,
+ REGISTER_AND_MOVE,
+};
+
+enum preempt_type {
+ PREEMPT,
+ PREEMPT_AND_ABORT,
+};
+
static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
struct t10_pr_registration *, int);
@@ -596,14 +606,6 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
return NULL;
}
- pr_reg->pr_aptpl_buf = kzalloc(dev->t10_pr.pr_aptpl_buf_len,
- GFP_ATOMIC);
- if (!pr_reg->pr_aptpl_buf) {
- pr_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);
@@ -794,7 +796,6 @@ int core_scsi3_alloc_aptpl_registration(
pr_err("Unable to allocate struct t10_pr_registration\n");
return -ENOMEM;
}
- 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);
@@ -848,11 +849,9 @@ static void core_scsi3_aptpl_reserve(
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
spin_lock(&dev->dev_reservation_lock);
dev->dev_pr_res_holder = pr_reg;
@@ -865,11 +864,11 @@ static void core_scsi3_aptpl_reserve(
(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",
tpg->se_tpg_tfo->get_fabric_name(), node_acl->initiatorname,
- (prf_isid) ? &i_buf[0] : "");
+ i_buf);
}
static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *,
- struct t10_pr_registration *, int, int);
+ struct t10_pr_registration *, enum register_type, int);
static int __core_scsi3_check_aptpl_registration(
struct se_device *dev,
@@ -962,21 +961,19 @@ static void __core_scsi3_dump_registration(
struct se_device *dev,
struct se_node_acl *nacl,
struct t10_pr_registration *pr_reg,
- int register_type)
+ enum register_type 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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
pr_debug("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) ?
+ " Node: %s%s\n", tfo->get_fabric_name(), (register_type == REGISTER_AND_MOVE) ?
+ "_AND_MOVE" : (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ?
"_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname,
- (prf_isid) ? i_buf : "");
+ i_buf);
pr_debug("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));
@@ -998,7 +995,7 @@ static void __core_scsi3_add_registration(
struct se_device *dev,
struct se_node_acl *nacl,
struct t10_pr_registration *pr_reg,
- int register_type,
+ enum register_type register_type,
int register_move)
{
struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
@@ -1064,7 +1061,7 @@ static int core_scsi3_alloc_registration(
u64 sa_res_key,
int all_tg_pt,
int aptpl,
- int register_type,
+ enum register_type register_type,
int register_move)
{
struct t10_pr_registration *pr_reg;
@@ -1225,11 +1222,9 @@ static void __core_scsi3_free_registration(
pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
pr_reg->pr_reg_deve->def_pr_registered = 0;
pr_reg->pr_reg_deve->pr_res_key = 0;
@@ -1257,7 +1252,7 @@ static void __core_scsi3_free_registration(
pr_debug("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] : "");
+ i_buf);
pr_debug("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",
@@ -1269,7 +1264,6 @@ static void __core_scsi3_free_registration(
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;
}
@@ -1338,7 +1332,6 @@ void core_scsi3_free_all_registrations(
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);
@@ -1453,7 +1446,7 @@ core_scsi3_decode_spec_i_port(
char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
sense_reason_t ret;
u32 tpdl, tid_len = 0;
- int dest_local_nexus, prf_isid;
+ int dest_local_nexus;
u32 dest_rtpi = 0;
memset(dest_iport, 0, 64);
@@ -1764,8 +1757,7 @@ core_scsi3_decode_spec_i_port(
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_pr_dump_initiator_port(dest_pr_reg, i_buf, PR_REG_ISID_ID_LEN);
__core_scsi3_add_registration(cmd->se_dev, dest_node_acl,
dest_pr_reg, 0, 0);
@@ -1773,8 +1765,7 @@ core_scsi3_decode_spec_i_port(
pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully"
" registered Transport ID for Node: %s%s Mapped LUN:"
" %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(),
- dest_node_acl->initiatorname, (prf_isid) ?
- &i_buf[0] : "", dest_se_deve->mapped_lun);
+ dest_node_acl->initiatorname, i_buf, dest_se_deve->mapped_lun);
if (dest_local_nexus)
continue;
@@ -1813,7 +1804,6 @@ out:
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)
@@ -1826,14 +1816,10 @@ out:
return ret;
}
-/*
- * Called with struct se_device->dev_reservation_lock held
- */
-static int __core_scsi3_update_aptpl_buf(
+static int core_scsi3_update_aptpl_buf(
struct se_device *dev,
unsigned char *buf,
- u32 pr_aptpl_buf_len,
- int clear_aptpl_metadata)
+ u32 pr_aptpl_buf_len)
{
struct se_lun *lun;
struct se_portal_group *tpg;
@@ -1841,20 +1827,13 @@ static int __core_scsi3_update_aptpl_buf(
unsigned char tmp[512], isid_buf[32];
ssize_t len = 0;
int reg_count = 0;
+ int ret = 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;
- }
+ spin_lock(&dev->dev_reservation_lock);
+ spin_lock(&dev->t10_pr.registration_lock);
/*
* Walk the registration list..
*/
- spin_lock(&dev->t10_pr.registration_lock);
list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,
pr_reg_list) {
@@ -1900,8 +1879,8 @@ static int __core_scsi3_update_aptpl_buf(
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
pr_err("Unable to update renaming"
" APTPL metadata\n");
- spin_unlock(&dev->t10_pr.registration_lock);
- return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ goto out;
}
len += sprintf(buf+len, "%s", tmp);
@@ -1918,48 +1897,32 @@ static int __core_scsi3_update_aptpl_buf(
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
pr_err("Unable to update renaming"
" APTPL metadata\n");
- spin_unlock(&dev->t10_pr.registration_lock);
- return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ goto out;
}
len += sprintf(buf+len, "%s", tmp);
reg_count++;
}
- spin_unlock(&dev->t10_pr.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);
+out:
+ spin_unlock(&dev->t10_pr.registration_lock);
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)
+ unsigned char *buf)
{
struct t10_wwn *wwn = &dev->t10_wwn;
struct file *file;
int flags = O_RDWR | O_CREAT | O_TRUNC;
char path[512];
+ u32 pr_aptpl_buf_len;
int ret;
memset(path, 0, 512);
@@ -1978,8 +1941,7 @@ static int __core_scsi3_write_aptpl_to_file(
return PTR_ERR(file);
}
- if (!pr_aptpl_buf_len)
- pr_aptpl_buf_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */
+ pr_aptpl_buf_len = (strlen(buf) + 1); /* Add extra for NULL */
ret = kernel_write(file, buf, pr_aptpl_buf_len, 0);
@@ -1990,60 +1952,64 @@ static int __core_scsi3_write_aptpl_to_file(
return ret ? -EIO : 0;
}
-static int
-core_scsi3_update_and_write_aptpl(struct se_device *dev, unsigned char *in_buf,
- u32 in_pr_aptpl_buf_len)
+/*
+ * Clear the APTPL metadata if APTPL has been disabled, otherwise
+ * write out the updated metadata to struct file for this SCSI device.
+ */
+static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl)
{
- unsigned char null_buf[64], *buf;
- u32 pr_aptpl_buf_len;
- int clear_aptpl_metadata = 0;
- int ret;
+ unsigned char *buf;
+ int rc;
- /*
- * 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;
+ if (!aptpl) {
+ char *null_buf = "No Registrations or Reservations\n";
+
+ rc = __core_scsi3_write_aptpl_to_file(dev, null_buf);
+ dev->t10_pr.pr_aptpl_active = 0;
+ pr_debug("SPC-3 PR: Set APTPL Bit Deactivated\n");
+
+ if (rc)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ return 0;
}
- ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
- clear_aptpl_metadata);
- if (ret != 0)
- return ret;
+ buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL);
+ if (!buf)
+ return TCM_OUT_OF_RESOURCES;
- /*
- * __core_scsi3_write_aptpl_to_file() will call strlen()
- * on the passed buf to determine pr_aptpl_buf_len.
- */
- return __core_scsi3_write_aptpl_to_file(dev, buf, 0);
+ rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN);
+ if (rc < 0) {
+ kfree(buf);
+ return TCM_OUT_OF_RESOURCES;
+ }
+
+ rc = __core_scsi3_write_aptpl_to_file(dev, buf);
+ if (rc != 0) {
+ pr_err("SPC-3 PR: Could not update APTPL\n");
+ kfree(buf);
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
+ dev->t10_pr.pr_aptpl_active = 1;
+ kfree(buf);
+ pr_debug("SPC-3 PR: Set APTPL Bit Activated\n");
+ return 0;
}
static sense_reason_t
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)
+ bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type)
{
struct se_session *se_sess = cmd->se_sess;
struct se_device *dev = cmd->se_dev;
struct se_dev_entry *se_deve;
struct se_lun *se_lun = cmd->se_lun;
struct se_portal_group *se_tpg;
- struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e;
+ struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
- /* Used for APTPL metadata w/ UNREGISTER */
- unsigned char *pr_aptpl_buf = NULL;
unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
sense_reason_t ret = TCM_NO_SENSE;
- int pr_holder = 0, type;
+ int pr_holder = 0;
if (!se_sess || !se_lun) {
pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
@@ -2061,8 +2027,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
/*
* 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) {
+ pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+ if (!pr_reg) {
if (res_key) {
pr_warn("SPC-3 PR: Reservation Key non-zero"
" for SA REGISTER, returning CONFLICT\n");
@@ -2083,7 +2049,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
if (core_scsi3_alloc_registration(cmd->se_dev,
se_sess->se_node_acl, se_deve, isid_ptr,
sa_res_key, all_tg_pt, aptpl,
- ignore_key, 0)) {
+ register_type, 0)) {
pr_err("Unable to allocate"
" struct t10_pr_registration\n");
return TCM_INVALID_PARAMETER_LIST;
@@ -2102,97 +2068,68 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
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(cmd->se_dev, NULL, 0);
- pr_debug("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(cmd->se_dev,
- se_sess->se_node_acl, se_sess);
-
- if (core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &pr_reg->pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_tmpl->pr_aptpl_active = 1;
- pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n");
- }
- goto out_put_pr_reg;
+ return core_scsi3_update_and_write_aptpl(dev, aptpl);
}
- /*
- * 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) {
- pr_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);
- ret = TCM_RESERVATION_CONFLICT;
- goto out_put_pr_reg;
- }
+ /* ok, existing registration */
+
+ if ((register_type == REGISTER) && (res_key != pr_reg->pr_res_key)) {
+ pr_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);
+ ret = TCM_RESERVATION_CONFLICT;
+ goto out;
}
if (spec_i_pt) {
- pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT"
- " set while sa_res_key=0\n");
+ pr_err("SPC-3 PR REGISTER: SPEC_I_PT"
+ " set on a registered nexus\n");
ret = TCM_INVALID_PARAMETER_LIST;
- goto out_put_pr_reg;
+ goto out;
}
/*
* 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)) {
- pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1"
+ if (pr_reg->pr_reg_all_tg_pt && !all_tg_pt) {
+ pr_err("SPC-3 PR REGISTER: ALL_TG_PT=1"
" registration exists, but ALL_TG_PT=1 bit not"
" present in received PROUT\n");
ret = TCM_INVALID_CDB_FIELD;
- goto out_put_pr_reg;
+ goto out;
}
/*
- * Allocate APTPL metadata buffer used for UNREGISTER ops
+ * sa_res_key=1 Change Reservation Key for registered I_T Nexus.
*/
- if (aptpl) {
- pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len,
- GFP_KERNEL);
- if (!pr_aptpl_buf) {
- pr_err("Unable to allocate"
- " pr_aptpl_buf\n");
- ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- goto out_put_pr_reg;
- }
- }
+ if (sa_res_key) {
+ /*
+ * 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(cmd->se_dev);
+ pr_reg->pr_res_key = sa_res_key;
+ pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
+ " Key for %s to: 0x%016Lx PRgeneration:"
+ " 0x%08x\n", cmd->se_tfo->get_fabric_name(),
+ (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ? "_AND_IGNORE_EXISTING_KEY" : "",
+ pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg->pr_res_key, pr_reg->pr_res_generation);
- /*
- * 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) {
+ } else {
+ /*
+ * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus.
+ */
pr_holder = core_scsi3_check_implict_release(
cmd->se_dev, pr_reg);
if (pr_holder < 0) {
- kfree(pr_aptpl_buf);
ret = TCM_RESERVATION_CONFLICT;
- goto out_put_pr_reg;
+ goto out;
}
spin_lock(&pr_tmpl->registration_lock);
@@ -2237,8 +2174,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
* RESERVATIONS RELEASED.
*/
if (pr_holder &&
- (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
- type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
+ (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
+ pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
list_for_each_entry(pr_reg_p,
&pr_tmpl->registration_list,
pr_reg_list) {
@@ -2250,60 +2187,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
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);
- pr_debug("SPC-3 PR: Set APTPL Bit Deactivated"
- " for UNREGISTER\n");
- return 0;
- }
- if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_tmpl->pr_aptpl_active = 1;
- pr_debug("SPC-3 PR: Set APTPL Bit Activated"
- " for UNREGISTER\n");
- }
-
- goto out_free_aptpl_buf;
- }
-
- /*
- * 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(cmd->se_dev);
- pr_reg->pr_res_key = sa_res_key;
- pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
- " Key for %s to: 0x%016Lx PRgeneration:"
- " 0x%08x\n", cmd->se_tfo->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);
- pr_debug("SPC-3 PR: Set APTPL Bit Deactivated"
- " for REGISTER\n");
- ret = 0;
- goto out_put_pr_reg;
+ spin_unlock(&pr_tmpl->registration_lock);
}
- if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_tmpl->pr_aptpl_active = 1;
- pr_debug("SPC-3 PR: Set APTPL Bit Activated"
- " for REGISTER\n");
- }
+ ret = core_scsi3_update_and_write_aptpl(dev, aptpl);
-out_free_aptpl_buf:
- kfree(pr_aptpl_buf);
- ret = 0;
-out_put_pr_reg:
+out:
core_scsi3_put_pr_reg(pr_reg);
return ret;
}
@@ -2340,7 +2230,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
struct t10_reservation *pr_tmpl = &dev->t10_pr;
char i_buf[PR_REG_ISID_ID_LEN];
sense_reason_t ret;
- int prf_isid;
memset(i_buf, 0, PR_REG_ISID_ID_LEN);
@@ -2466,8 +2355,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
pr_debug("SPC-3 PR [%s] Service Action: RESERVE created new"
" reservation holder TYPE: %s ALL_TG_PT: %d\n",
@@ -2476,17 +2364,11 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",
cmd->se_tfo->get_fabric_name(),
se_sess->se_node_acl->initiatorname,
- (prf_isid) ? &i_buf[0] : "");
+ i_buf);
spin_unlock(&dev->dev_reservation_lock);
- if (pr_tmpl->pr_aptpl_active) {
- if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &pr_reg->pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_debug("SPC-3 PR: Updated APTPL metadata"
- " for RESERVE\n");
- }
- }
+ if (pr_tmpl->pr_aptpl_active)
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
ret = 0;
out_put_pr_reg:
@@ -2524,11 +2406,9 @@ static void __core_scsi3_complete_pro_release(
{
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
/*
* Go ahead and release the current PR reservation holder.
*/
@@ -2541,7 +2421,7 @@ static void __core_scsi3_complete_pro_release(
(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n",
tfo->get_fabric_name(), se_nacl->initiatorname,
- (prf_isid) ? &i_buf[0] : "");
+ i_buf);
/*
* Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE
*/
@@ -2702,12 +2582,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
spin_unlock(&pr_tmpl->registration_lock);
write_aptpl:
- if (pr_tmpl->pr_aptpl_active) {
- if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &pr_reg->pr_aptpl_buf[0], pr_tmpl->pr_aptpl_buf_len)) {
- pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n");
- }
- }
+ if (pr_tmpl->pr_aptpl_active)
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
+
out_put_pr_reg:
core_scsi3_put_pr_reg(pr_reg);
return ret;
@@ -2791,11 +2668,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)
pr_debug("SPC-3 PR [%s] Service Action: CLEAR complete\n",
cmd->se_tfo->get_fabric_name());
- if (pr_tmpl->pr_aptpl_active) {
- core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0);
- pr_debug("SPC-3 PR: Updated APTPL metadata"
- " for CLEAR\n");
- }
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, false);
core_scsi3_pr_generation(dev);
return 0;
@@ -2810,16 +2683,14 @@ static void __core_scsi3_complete_pro_preempt(
struct list_head *preempt_and_abort_list,
int type,
int scope,
- int abort)
+ enum preempt_type preempt_type)
{
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
/*
* Do an implict RELEASE of the existing reservation.
*/
@@ -2834,12 +2705,12 @@ static void __core_scsi3_complete_pro_preempt(
pr_debug("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" : "",
+ tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "",
core_scsi3_pr_dump_type(type),
(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
pr_debug("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] : "");
+ tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "",
+ nacl->initiatorname, i_buf);
/*
* For PREEMPT_AND_ABORT, add the preempting reservation's
* struct t10_pr_registration to the list that will be compared
@@ -2869,14 +2740,13 @@ static void core_scsi3_release_preempt_and_abort(
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);
}
}
static sense_reason_t
core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
- u64 sa_res_key, int abort)
+ u64 sa_res_key, enum preempt_type preempt_type)
{
struct se_device *dev = cmd->se_dev;
struct se_node_acl *pr_reg_nacl;
@@ -2896,7 +2766,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
if (!pr_reg_n) {
pr_err("SPC-3 PR: Unable to locate"
" PR_REGISTERED *pr_reg for PREEMPT%s\n",
- (abort) ? "_AND_ABORT" : "");
+ (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "");
return TCM_RESERVATION_CONFLICT;
}
if (pr_reg_n->pr_res_key != res_key) {
@@ -2965,7 +2835,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
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 :
+ (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
NULL, calling_it_nexus);
released_regs++;
} else {
@@ -2993,7 +2863,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
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 :
+ (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
NULL, 0);
released_regs++;
}
@@ -3022,24 +2892,17 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
*/
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);
+ (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
+ type, scope, preempt_type);
- if (abort)
+ if (preempt_type == PREEMPT_AND_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) {
- if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &pr_reg_n->pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_debug("SPC-3 PR: Updated APTPL"
- " metadata for PREEMPT%s\n", (abort) ?
- "_AND_ABORT" : "");
- }
- }
+ if (pr_tmpl->pr_aptpl_active)
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
core_scsi3_put_pr_reg(pr_reg_n);
core_scsi3_pr_generation(cmd->se_dev);
@@ -3103,7 +2966,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
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,
+ (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
calling_it_nexus);
/*
* e) Establish a unit attention condition for the initiator
@@ -3120,8 +2983,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
* 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);
+ (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
+ type, scope, preempt_type);
/*
* d) Process tasks as defined in 5.7.1;
* e) See above..
@@ -3161,20 +3024,14 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
* been removed from the primary pr_reg list), except the
* new persistent reservation holder, the calling Initiator Port.
*/
- if (abort) {
+ if (preempt_type == PREEMPT_AND_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) {
- if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &pr_reg_n->pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT"
- "%s\n", abort ? "_AND_ABORT" : "");
- }
- }
+ if (pr_tmpl->pr_aptpl_active)
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
core_scsi3_put_pr_reg(pr_reg_n);
core_scsi3_pr_generation(cmd->se_dev);
@@ -3183,7 +3040,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
static sense_reason_t
core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,
- u64 res_key, u64 sa_res_key, int abort)
+ u64 res_key, u64 sa_res_key, enum preempt_type preempt_type)
{
switch (type) {
case PR_TYPE_WRITE_EXCLUSIVE:
@@ -3193,10 +3050,10 @@ core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,
case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
return core_scsi3_pro_preempt(cmd, type, scope, res_key,
- sa_res_key, abort);
+ sa_res_key, preempt_type);
default:
pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s"
- " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type);
+ " Type: 0x%02x\n", (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "", type);
return TCM_INVALID_CDB_FIELD;
}
}
@@ -3220,7 +3077,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
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, matching_iname, prf_isid;
+ int new_reg = 0, type, scope, matching_iname;
sense_reason_t ret;
unsigned short rtpi;
unsigned char proto_ident;
@@ -3564,8 +3421,7 @@ after_iport_check:
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);
+ core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
/*
* Increment PRGeneration for existing registrations..
*/
@@ -3581,7 +3437,7 @@ after_iport_check:
pr_debug("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(),
+ i_buf, dest_tf_ops->get_fabric_name(),
dest_node_acl->initiatorname, (iport_ptr != NULL) ?
iport_ptr : "");
/*
@@ -3602,24 +3458,7 @@ after_iport_check:
} 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(cmd->se_dev, NULL, 0);
- pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for"
- " REGISTER_AND_MOVE\n");
- } else {
- pr_tmpl->pr_aptpl_active = 1;
- if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
- &dest_pr_reg->pr_aptpl_buf[0],
- pr_tmpl->pr_aptpl_buf_len)) {
- pr_debug("SPC-3 PR: Set APTPL Bit Activated for"
- " REGISTER_AND_MOVE\n");
- }
- }
+ core_scsi3_update_and_write_aptpl(cmd->se_dev, aptpl);
transport_kunmap_data_sg(cmd);
@@ -3752,7 +3591,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
switch (sa) {
case PRO_REGISTER:
ret = core_scsi3_emulate_pro_register(cmd,
- res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0);
+ res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER);
break;
case PRO_RESERVE:
ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key);
@@ -3765,15 +3604,15 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
break;
case PRO_PREEMPT:
ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
- res_key, sa_res_key, 0);
+ res_key, sa_res_key, PREEMPT);
break;
case PRO_PREEMPT_AND_ABORT:
ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
- res_key, sa_res_key, 1);
+ res_key, sa_res_key, PREEMPT_AND_ABORT);
break;
case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
ret = core_scsi3_emulate_pro_register(cmd,
- 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1);
+ 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER_AND_IGNORE_EXISTING_KEY);
break;
case PRO_REGISTER_AND_MOVE:
ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key,
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index b4a004247ab2..ed75cdd32cb0 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -45,7 +45,7 @@
extern struct kmem_cache *t10_pr_reg_cache;
-extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
+extern void core_pr_dump_initiator_port(struct t10_pr_registration *,
char *, u32);
extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *);
extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *);
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 0921a64b5550..51127d15d5c5 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -139,6 +139,11 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
rd_dev->rd_page_count);
return -EINVAL;
}
+
+ /* Don't need backing pages for NULLIO */
+ if (rd_dev->rd_flags & RDF_NULLIO)
+ return 0;
+
total_sg_needed = rd_dev->rd_page_count;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index bbc5b0ee2bdc..8a462773d0c8 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -38,11 +38,27 @@ static sense_reason_t
sbc_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
+ unsigned char *cdb = cmd->t_task_cdb;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
unsigned char *rbuf;
unsigned char buf[8];
u32 blocks;
+ /*
+ * SBC-2 says:
+ * If the PMI bit is set to zero and the LOGICAL BLOCK
+ * ADDRESS field is not set to zero, the device server shall
+ * terminate the command with CHECK CONDITION status with
+ * the sense key set to ILLEGAL REQUEST and the additional
+ * sense code set to INVALID FIELD IN CDB.
+ *
+ * In SBC-3, these fields are obsolete, but some SCSI
+ * compliance tests actually check this, so we might as well
+ * follow SBC-2.
+ */
+ if (!(cdb[8] & 1) && !!(cdb[2] | cdb[3] | cdb[4] | cdb[5]))
+ return TCM_INVALID_CDB_FIELD;
+
if (blocks_long >= 0x00000000ffffffff)
blocks = 0xffffffff;
else
@@ -581,7 +597,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
pr_err("cmd exceeds last lba %llu "
"(lba %llu, sectors %u)\n",
end_lba, cmd->t_task_lba, sectors);
- return TCM_INVALID_CDB_FIELD;
+ return TCM_ADDRESS_OUT_OF_RANGE;
}
size = sbc_get_size(cmd, sectors);
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index d0b4dd95b91e..0d7cacb91107 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -85,13 +85,8 @@ void core_tmr_release_req(
static void core_tmr_handle_tas_abort(
struct se_node_acl *tmr_nacl,
struct se_cmd *cmd,
- int tas,
- int fe_count)
+ int tas)
{
- if (!fe_count) {
- transport_cmd_finish_abort(cmd, 1);
- return;
- }
/*
* TASK ABORTED status (TAS) bit support
*/
@@ -253,7 +248,6 @@ static void core_tmr_drain_state_list(
LIST_HEAD(drain_task_list);
struct se_cmd *cmd, *next;
unsigned long flags;
- int fe_count;
/*
* Complete outstanding commands with TASK_ABORTED SAM status.
@@ -329,12 +323,10 @@ static void core_tmr_drain_state_list(
spin_lock_irqsave(&cmd->t_state_lock, flags);
target_stop_cmd(cmd, &flags);
- fe_count = atomic_read(&cmd->t_fe_count);
-
cmd->transport_state |= CMD_T_ABORTED;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
}
}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 21e315874a54..7172d005d063 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -52,6 +52,9 @@
#include "target_core_pr.h"
#include "target_core_ua.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/target.h>
+
static struct workqueue_struct *target_completion_wq;
static struct kmem_cache *se_sess_cache;
struct kmem_cache *se_ua_cache;
@@ -446,11 +449,15 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
-static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)
+static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists,
+ bool write_pending)
{
unsigned long flags;
spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if (write_pending)
+ cmd->t_state = TRANSPORT_WRITE_PENDING;
+
/*
* Determine if IOCTL context caller in requesting the stopping of this
* command for LUN shutdown purposes.
@@ -515,7 +522,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)
static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
{
- return transport_cmd_check_stop(cmd, true);
+ return transport_cmd_check_stop(cmd, true, false);
}
static void transport_lun_remove_cmd(struct se_cmd *cmd)
@@ -526,13 +533,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
if (!lun)
return;
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
- cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
- target_remove_from_state_list(cmd);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
spin_lock_irqsave(&lun->lun_cmd_lock, flags);
if (!list_empty(&cmd->se_lun_node))
list_del_init(&cmd->se_lun_node);
@@ -1092,7 +1092,6 @@ sense_reason_t
target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
{
struct se_device *dev = cmd->se_dev;
- unsigned long flags;
sense_reason_t ret;
/*
@@ -1127,6 +1126,8 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
*/
memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb));
+ trace_target_sequencer_start(cmd);
+
/*
* Check for an existing UNIT ATTENTION condition
*/
@@ -1152,9 +1153,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
if (ret)
return ret;
- spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
spin_lock(&cmd->se_lun->lun_sep_lock);
if (cmd->se_lun->lun_sep)
@@ -1552,7 +1551,8 @@ void transport_generic_request_failure(struct se_cmd *cmd,
cmd->orig_fe_lun, 0x2C,
ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
- ret = cmd->se_tfo->queue_status(cmd);
+ trace_target_cmd_complete(cmd);
+ ret = cmd->se_tfo-> queue_status(cmd);
if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
goto check_stop;
@@ -1583,10 +1583,6 @@ static void __target_execute_cmd(struct se_cmd *cmd)
{
sense_reason_t ret;
- spin_lock_irq(&cmd->t_state_lock);
- cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT);
- spin_unlock_irq(&cmd->t_state_lock);
-
if (cmd->execute_cmd) {
ret = cmd->execute_cmd(cmd);
if (ret) {
@@ -1693,11 +1689,17 @@ void target_execute_cmd(struct se_cmd *cmd)
}
cmd->t_state = TRANSPORT_PROCESSING;
- cmd->transport_state |= CMD_T_ACTIVE;
+ cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
spin_unlock_irq(&cmd->t_state_lock);
- if (!target_handle_task_attr(cmd))
- __target_execute_cmd(cmd);
+ if (target_handle_task_attr(cmd)) {
+ spin_lock_irq(&cmd->t_state_lock);
+ cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
+ spin_unlock_irq(&cmd->t_state_lock);
+ return;
+ }
+
+ __target_execute_cmd(cmd);
}
EXPORT_SYMBOL(target_execute_cmd);
@@ -1770,6 +1772,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
transport_complete_task_attr(cmd);
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+ trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_status(cmd);
if (ret)
goto out;
@@ -1777,6 +1780,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
switch (cmd->data_direction) {
case DMA_FROM_DEVICE:
+ trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_data_in(cmd);
break;
case DMA_TO_DEVICE:
@@ -1787,6 +1791,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
}
/* Fall through for DMA_TO_DEVICE */
case DMA_NONE:
+ trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_status(cmd);
break;
default:
@@ -1865,6 +1870,7 @@ static void target_complete_ok_work(struct work_struct *work)
}
spin_unlock(&cmd->se_lun->lun_sep_lock);
+ trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_data_in(cmd);
if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
@@ -1893,6 +1899,7 @@ static void target_complete_ok_work(struct work_struct *work)
}
/* Fall through for DMA_TO_DEVICE */
case DMA_NONE:
+ trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_status(cmd);
if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full;
@@ -1956,11 +1963,7 @@ static int transport_release_cmd(struct se_cmd *cmd)
* If this cmd has been setup with target_get_sess_cmd(), drop
* the kref and call ->release_cmd() in kref callback.
*/
- if (cmd->check_release != 0)
- return target_put_sess_cmd(cmd->se_sess, cmd);
-
- cmd->se_tfo->release_cmd(cmd);
- return 1;
+ return target_put_sess_cmd(cmd->se_sess, cmd);
}
/**
@@ -1971,21 +1974,6 @@ static int transport_release_cmd(struct se_cmd *cmd)
*/
static int transport_put_cmd(struct se_cmd *cmd)
{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (atomic_read(&cmd->t_fe_count) &&
- !atomic_dec_and_test(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return 0;
- }
-
- if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
- cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
- target_remove_from_state_list(cmd);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
transport_free_pages(cmd);
return transport_release_cmd(cmd);
}
@@ -2103,9 +2091,6 @@ transport_generic_new_cmd(struct se_cmd *cmd)
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
-
- atomic_inc(&cmd->t_fe_count);
-
/*
* If this command is not a write we can execute it right here,
* for write buffers we need to notify the fabric driver first
@@ -2116,12 +2101,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)
target_execute_cmd(cmd);
return 0;
}
-
- spin_lock_irq(&cmd->t_state_lock);
- cmd->t_state = TRANSPORT_WRITE_PENDING;
- spin_unlock_irq(&cmd->t_state_lock);
-
- transport_cmd_check_stop(cmd, false);
+ transport_cmd_check_stop(cmd, false, true);
ret = cmd->se_tfo->write_pending(cmd);
if (ret == -EAGAIN || ret == -ENOMEM)
@@ -2202,8 +2182,6 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
goto out;
}
list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
- se_cmd->check_release = 1;
-
out:
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
return ret;
@@ -2319,7 +2297,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n",
cmd->se_tfo->get_task_tag(cmd));
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_cmd_check_stop(cmd, false);
+ transport_cmd_check_stop(cmd, false, false);
return -EPERM;
}
cmd->transport_state |= CMD_T_LUN_FE_STOP;
@@ -2427,7 +2405,7 @@ check_cond:
spin_unlock_irqrestore(&cmd->t_state_lock,
cmd_flags);
- transport_cmd_check_stop(cmd, false);
+ transport_cmd_check_stop(cmd, false, false);
complete(&cmd->transport_lun_fe_stop_comp);
spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
continue;
@@ -2778,6 +2756,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
after_reason:
+ trace_target_cmd_complete(cmd);
return cmd->se_tfo->queue_status(cmd);
}
EXPORT_SYMBOL(transport_send_check_condition_and_sense);
@@ -2794,6 +2773,7 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd));
cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
+ trace_target_cmd_complete(cmd);
cmd->se_tfo->queue_status(cmd);
return 1;
@@ -2831,6 +2811,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
" ITT: 0x%08x\n", cmd->t_task_cdb[0],
cmd->se_tfo->get_task_tag(cmd));
+ trace_target_cmd_complete(cmd);
cmd->se_tfo->queue_status(cmd);
}
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index eea69358ced3..0dd54a44abcf 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -161,7 +161,7 @@ int ft_write_pending(struct se_cmd *);
int ft_write_pending_status(struct se_cmd *);
u32 ft_get_task_tag(struct se_cmd *);
int ft_get_cmd_state(struct se_cmd *);
-int ft_queue_tm_resp(struct se_cmd *);
+void ft_queue_tm_resp(struct se_cmd *);
/*
* other internal functions.
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index b406f178ff39..0e5a1caed176 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -394,14 +394,14 @@ static void ft_send_tm(struct ft_cmd *cmd)
/*
* Send status from completed task management request.
*/
-int ft_queue_tm_resp(struct se_cmd *se_cmd)
+void ft_queue_tm_resp(struct se_cmd *se_cmd)
{
struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
struct se_tmr_req *tmr = se_cmd->se_tmr_req;
enum fcp_resp_rsp_codes code;
if (cmd->aborted)
- return 0;
+ return;
switch (tmr->response) {
case TMR_FUNCTION_COMPLETE:
code = FCP_TMF_CMPL;
@@ -413,10 +413,7 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
code = FCP_TMF_REJECTED;
break;
case TMR_TASK_DOES_NOT_EXIST:
- case TMR_TASK_STILL_ALLEGIANT:
- case TMR_TASK_FAILOVER_NOT_SUPPORTED:
case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
- case TMR_FUNCTION_AUTHORIZATION_FAILED:
default:
code = FCP_TMF_FAILED;
break;
@@ -424,7 +421,6 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
pr_debug("tmr fn %d resp %d fcp code %d\n",
tmr->function, tmr->response, code);
ft_send_resp_code(cmd, code);
- return 0;
}
static void ft_send_work(struct work_struct *work);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5e3c02554d99..e988c81d763c 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -169,4 +169,19 @@ config INTEL_POWERCLAMP
enforce idle time which results in more package C-state residency. The
user interface is exposed via generic thermal framework.
+config X86_PKG_TEMP_THERMAL
+ tristate "X86 package temperature thermal driver"
+ depends on X86_THERMAL_VECTOR
+ select THERMAL_GOV_USER_SPACE
+ default m
+ help
+ Enable this to register CPU digital sensor for package temperature as
+ thermal zone. Each package will have its own thermal zone. There are
+ two trip points which can be set by user to get notifications via thermal
+ notification methods.
+
+menu "Texas Instruments thermal drivers"
+source "drivers/thermal/ti-soc-thermal/Kconfig"
+endmenu
+
endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c054d410ac3f..67184a293e3f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -23,4 +23,5 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
-
+obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
+obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 54ffd64ca3f7..5e53212b984f 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -200,7 +200,6 @@ static int armada_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(armada_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -211,7 +210,7 @@ static struct platform_driver armada_thermal_driver = {
.driver = {
.name = "armada_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(armada_thermal_id_table),
+ .of_match_table = armada_thermal_id_table,
},
};
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index c94bf2e5de62..82e15dbb3ac7 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -167,7 +167,7 @@ static int get_property(unsigned int cpu, unsigned long input,
continue;
/* get the frequency order */
- if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
+ if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
descend = !!(freq > table[i].frequency);
freq = table[i].frequency;
diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
index a088d1365ca5..828f5e345c30 100644
--- a/drivers/thermal/dove_thermal.c
+++ b/drivers/thermal/dove_thermal.c
@@ -134,16 +134,11 @@ static int dove_thermal_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
@@ -178,7 +173,6 @@ static int dove_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(dove_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -191,7 +185,7 @@ static struct platform_driver dove_thermal_driver = {
.driver = {
.name = "dove_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(dove_thermal_id_table),
+ .of_match_table = dove_thermal_id_table,
},
};
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 4cbe3eea6deb..9af4b93c9f86 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -997,7 +997,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
return 0;
err_clk:
- platform_set_drvdata(pdev, NULL);
clk_unprepare(data->clk);
return ret;
}
@@ -1012,8 +1011,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
clk_unprepare(data->clk);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c
index dfeceaffbc03..3b034a0dfc94 100644
--- a/drivers/thermal/kirkwood_thermal.c
+++ b/drivers/thermal/kirkwood_thermal.c
@@ -75,16 +75,11 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
struct kirkwood_thermal_priv *priv;
struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
@@ -108,7 +103,6 @@ static int kirkwood_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(kirkwood_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -121,7 +115,7 @@ static struct platform_driver kirkwood_thermal_driver = {
.driver = {
.name = "kirkwood_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(kirkwood_thermal_id_table),
+ .of_match_table = kirkwood_thermal_id_table,
},
};
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 8d7edd4c8228..88f92e1a9944 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -389,11 +389,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
* platform has IRQ support.
* Then, drier use common register
*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
- if (!res) {
- dev_err(dev, "Could not get platform resource\n");
- return -ENODEV;
- }
ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
dev_name(dev), common);
@@ -405,6 +400,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
/*
* rcar_has_irq_support() will be enabled
*/
+ res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
common->base = devm_ioremap_resource(dev, res);
if (IS_ERR(common->base))
return PTR_ERR(common->base);
@@ -458,7 +454,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, common);
- dev_info(dev, "%d sensor proved\n", i);
+ dev_info(dev, "%d sensor probed\n", i);
return 0;
@@ -487,8 +483,6 @@ static int rcar_thermal_remove(struct platform_device *pdev)
rcar_thermal_irq_disable(priv);
}
- platform_set_drvdata(pdev, NULL);
-
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index 3c5ee5607977..ab79ea4701d9 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -104,7 +104,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
struct thermal_zone_device *spear_thermal = NULL;
struct spear_thermal_dev *stdev;
struct device_node *np = pdev->dev.of_node;
- struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *res;
int ret = 0, val;
if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
@@ -112,11 +112,6 @@ static int spear_thermal_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!stres) {
- dev_err(&pdev->dev, "memory resource missing\n");
- return -ENODEV;
- }
-
stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
if (!stdev) {
dev_err(&pdev->dev, "kzalloc fail\n");
@@ -124,12 +119,10 @@ static int spear_thermal_probe(struct platform_device *pdev)
}
/* Enable thermal sensor */
- stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start,
- resource_size(stres));
- if (!stdev->thermal_base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ stdev->thermal_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(stdev->thermal_base))
+ return PTR_ERR(stdev->thermal_base);
stdev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(stdev->clk)) {
@@ -174,7 +167,6 @@ static int spear_thermal_exit(struct platform_device *pdev)
struct spear_thermal_dev *stdev = spear_thermal->devdata;
thermal_zone_device_unregister(spear_thermal);
- platform_set_drvdata(pdev, NULL);
/* Disable SPEAr Thermal Sensor */
actual_mask = readl_relaxed(stdev->thermal_base);
@@ -198,7 +190,7 @@ static struct platform_driver spear_thermal_driver = {
.name = "spear_thermal",
.owner = THIS_MODULE,
.pm = &spear_thermal_pm_ops,
- .of_match_table = of_match_ptr(spear_thermal_id_table),
+ .of_match_table = spear_thermal_id_table,
},
};
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index d755440791b7..1f02e8edb45c 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -33,6 +33,7 @@
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/reboot.h>
+#include <linux/string.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -155,7 +156,8 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip)
{
enum thermal_trend trend;
- if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+ if (tz->emul_temperature || !tz->ops->get_trend ||
+ tz->ops->get_trend(tz, trip, &trend)) {
if (tz->temperature > tz->last_temperature)
trend = THERMAL_TREND_RAISING;
else if (tz->temperature < tz->last_temperature)
@@ -713,10 +715,13 @@ policy_store(struct device *dev, struct device_attribute *attr,
int ret = -EINVAL;
struct thermal_zone_device *tz = to_thermal_zone(dev);
struct thermal_governor *gov;
+ char name[THERMAL_NAME_LENGTH];
+
+ snprintf(name, sizeof(name), "%s", buf);
mutex_lock(&thermal_governor_lock);
- gov = __find_governor(buf);
+ gov = __find_governor(strim(name));
if (!gov)
goto exit;
@@ -1624,7 +1629,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
if (!ops || !ops->get_temp)
return ERR_PTR(-EINVAL);
- if (trips > 0 && !ops->get_trip_type)
+ if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
return ERR_PTR(-EINVAL);
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
diff --git a/drivers/staging/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
index e81375fb2155..bd4c7beba679 100644
--- a/drivers/staging/ti-soc-thermal/Kconfig
+++ b/drivers/thermal/ti-soc-thermal/Kconfig
@@ -46,3 +46,15 @@ config OMAP5_THERMAL
This includes alert interrupts generation and also the TSHUT
support.
+
+config DRA752_THERMAL
+ bool "Texas Instruments DRA752 thermal support"
+ depends on TI_SOC_THERMAL
+ depends on SOC_DRA7XX
+ help
+ If you say yes here you get thermal support for the Texas Instruments
+ DRA752 SoC family. The current chip supported are:
+ - DRA752
+
+ This includes alert interrupts generation and also the TSHUT
+ support.
diff --git a/drivers/staging/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile
index 0ca034fb419d..1226b2484e55 100644
--- a/drivers/staging/ti-soc-thermal/Makefile
+++ b/drivers/thermal/ti-soc-thermal/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o
ti-soc-thermal-y := ti-bandgap.o
ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o
+ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/staging/ti-soc-thermal/TODO b/drivers/thermal/ti-soc-thermal/TODO
index 7da787d19241..7da787d19241 100644
--- a/drivers/staging/ti-soc-thermal/TODO
+++ b/drivers/thermal/ti-soc-thermal/TODO
diff --git a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
new file mode 100644
index 000000000000..6b0f2b1160f7
--- /dev/null
+++ b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
@@ -0,0 +1,280 @@
+/*
+ * DRA752 bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This is an auto generated file.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __DRA752_BANDGAP_H
+#define __DRA752_BANDGAP_H
+
+/**
+ * *** DRA752 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for DRA752.
+ */
+
+/**
+ * DRA752 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP_GPU on DRA752.
+ * DRA752_BANDGAP_BASE 0x4a0021e0
+ *
+ * Register below are grouped by domain (not necessarily in offset order)
+ */
+
+
+/* DRA752.common register offsets */
+#define DRA752_BANDGAP_CTRL_1_OFFSET 0x1a0
+#define DRA752_BANDGAP_STATUS_1_OFFSET 0x1c8
+#define DRA752_BANDGAP_CTRL_2_OFFSET 0x39c
+#define DRA752_BANDGAP_STATUS_2_OFFSET 0x3b8
+
+/* DRA752.core register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET 0x8
+#define DRA752_TEMP_SENSOR_CORE_OFFSET 0x154
+#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
+#define DRA752_BANDGAP_TSHUT_CORE_OFFSET 0x1b8
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
+#define DRA752_DTEMP_CORE_0_OFFSET 0x208
+#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
+#define DRA752_DTEMP_CORE_2_OFFSET 0x210
+#define DRA752_DTEMP_CORE_3_OFFSET 0x214
+#define DRA752_DTEMP_CORE_4_OFFSET 0x218
+
+/* DRA752.iva register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
+#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
+#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
+#define DRA752_BANDGAP_TSHUT_IVA_OFFSET 0x3ac
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
+#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
+#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
+#define DRA752_DTEMP_IVA_2_OFFSET 0x3d8
+#define DRA752_DTEMP_IVA_3_OFFSET 0x3dc
+#define DRA752_DTEMP_IVA_4_OFFSET 0x3e0
+
+/* DRA752.mpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
+#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
+#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
+#define DRA752_BANDGAP_TSHUT_MPU_OFFSET 0x1b0
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
+#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
+#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
+#define DRA752_DTEMP_MPU_2_OFFSET 0x1e8
+#define DRA752_DTEMP_MPU_3_OFFSET 0x1ec
+#define DRA752_DTEMP_MPU_4_OFFSET 0x1f0
+
+/* DRA752.dspeve register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
+#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
+#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
+#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET 0x3a8
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
+#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
+#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
+#define DRA752_DTEMP_DSPEVE_2_OFFSET 0x3c4
+#define DRA752_DTEMP_DSPEVE_3_OFFSET 0x3c8
+#define DRA752_DTEMP_DSPEVE_4_OFFSET 0x3cc
+
+/* DRA752.gpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
+#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
+#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
+#define DRA752_BANDGAP_TSHUT_GPU_OFFSET 0x1b4
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
+#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
+#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
+#define DRA752_DTEMP_GPU_2_OFFSET 0x1fc
+#define DRA752_DTEMP_GPU_3_OFFSET 0x200
+#define DRA752_DTEMP_GPU_4_OFFSET 0x204
+
+/**
+ * Register bitfields for DRA752
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on DRA752. Bit defines are
+ * grouped by register.
+ */
+
+/* DRA752.BANDGAP_STATUS_1 */
+#define DRA752_BANDGAP_STATUS_1_ALERT_MASK BIT(31)
+#define DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK BIT(5)
+#define DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK BIT(4)
+#define DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK BIT(3)
+#define DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK BIT(2)
+#define DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK BIT(1)
+#define DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK BIT(0)
+
+/* DRA752.BANDGAP_CTRL_2 */
+#define DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK BIT(22)
+#define DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK BIT(21)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK BIT(19)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK BIT(18)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK BIT(16)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK BIT(15)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK BIT(3)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK BIT(2)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK BIT(1)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK BIT(0)
+
+/* DRA752.BANDGAP_STATUS_2 */
+#define DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK BIT(3)
+#define DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK BIT(2)
+#define DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK BIT(1)
+#define DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK BIT(0)
+
+/* DRA752.BANDGAP_CTRL_1 */
+#define DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK (0x3 << 30)
+#define DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK (0x7 << 27)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK BIT(23)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK BIT(22)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK BIT(21)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK BIT(20)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK BIT(19)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK BIT(18)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK BIT(17)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK BIT(16)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK BIT(15)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK BIT(5)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK BIT(4)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK BIT(3)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK BIT(2)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK BIT(1)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK BIT(0)
+
+/* DRA752.TEMP_SENSOR */
+#define DRA752_TEMP_SENSOR_TMPSOFF_MASK BIT(11)
+#define DRA752_TEMP_SENSOR_EOCZ_MASK BIT(10)
+#define DRA752_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* DRA752.BANDGAP_THRESHOLD */
+#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
+#define DRA752_BANDGAP_THRESHOLD_COLD_MASK (0x3ff << 0)
+
+/* DRA752.TSHUT_THRESHOLD */
+#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK BIT(31)
+#define DRA752_TSHUT_THRESHOLD_HOT_MASK (0x3ff << 16)
+#define DRA752_TSHUT_THRESHOLD_COLD_MASK (0x3ff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_IVA */
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_MPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_DSPEVE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_GPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_MASK (0xffffffff << 0)
+
+/**
+ * Temperature limits and thresholds for DRA752
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for DRA752. Definitions are grouped
+ * by temperature domain.
+ */
+
+/* DRA752.common temperature definitions */
+/* ADC conversion table limits */
+#define DRA752_ADC_START_VALUE 540
+#define DRA752_ADC_END_VALUE 945
+
+/* DRA752.GPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_GPU_MAX_FREQ 1500000
+#define DRA752_GPU_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_GPU_MIN_TEMP -40000
+#define DRA752_GPU_MAX_TEMP 125000
+#define DRA752_GPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_GPU_TSHUT_HOT 915
+#define DRA752_GPU_TSHUT_COLD 900
+#define DRA752_GPU_T_HOT 800
+#define DRA752_GPU_T_COLD 795
+
+/* DRA752.MPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_MPU_MAX_FREQ 1500000
+#define DRA752_MPU_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_MPU_MIN_TEMP -40000
+#define DRA752_MPU_MAX_TEMP 125000
+#define DRA752_MPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_MPU_TSHUT_HOT 915
+#define DRA752_MPU_TSHUT_COLD 900
+#define DRA752_MPU_T_HOT 800
+#define DRA752_MPU_T_COLD 795
+
+/* DRA752.CORE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_CORE_MAX_FREQ 1500000
+#define DRA752_CORE_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_CORE_MIN_TEMP -40000
+#define DRA752_CORE_MAX_TEMP 125000
+#define DRA752_CORE_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_CORE_TSHUT_HOT 915
+#define DRA752_CORE_TSHUT_COLD 900
+#define DRA752_CORE_T_HOT 800
+#define DRA752_CORE_T_COLD 795
+
+/* DRA752.DSPEVE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_DSPEVE_MAX_FREQ 1500000
+#define DRA752_DSPEVE_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_DSPEVE_MIN_TEMP -40000
+#define DRA752_DSPEVE_MAX_TEMP 125000
+#define DRA752_DSPEVE_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_DSPEVE_TSHUT_HOT 915
+#define DRA752_DSPEVE_TSHUT_COLD 900
+#define DRA752_DSPEVE_T_HOT 800
+#define DRA752_DSPEVE_T_COLD 795
+
+/* DRA752.IVA temperature definitions */
+/* bandgap clock limits */
+#define DRA752_IVA_MAX_FREQ 1500000
+#define DRA752_IVA_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_IVA_MIN_TEMP -40000
+#define DRA752_IVA_MAX_TEMP 125000
+#define DRA752_IVA_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_IVA_TSHUT_HOT 915
+#define DRA752_IVA_TSHUT_COLD 900
+#define DRA752_IVA_T_HOT 800
+#define DRA752_IVA_T_COLD 795
+
+#endif /* __DRA752_BANDGAP_H */
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
new file mode 100644
index 000000000000..e5d8326a54d6
--- /dev/null
+++ b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
@@ -0,0 +1,476 @@
+/*
+ * DRA752 thermal data.
+ *
+ * Copyright (C) 2013 Texas Instruments Inc.
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This file is partially autogenerated.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+#include "dra752-bandgap.h"
+
+/*
+ * DRA752 has five instances of thermal sensor: MPU, GPU, CORE,
+ * IVA and DSPEVE need to describe the individual registers and
+ * bit fields.
+ */
+
+/*
+ * DRA752 CORE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_core_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_CORE_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_CORE_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_CORE_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_CORE_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_CORE_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_CORE_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET,
+};
+
+/*
+ * DRA752 IVA thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_iva_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_IVA_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_IVA_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_IVA_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_IVA_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_IVA_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_IVA_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET,
+};
+
+/*
+ * DRA752 MPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_mpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_MPU_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_MPU_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_MPU_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_MPU_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_MPU_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_MPU_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET,
+};
+
+/*
+ * DRA752 DSPEVE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_dspeve_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_DSPEVE_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_DSPEVE_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_DSPEVE_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_DSPEVE_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_DSPEVE_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_DSPEVE_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET,
+};
+
+/*
+ * DRA752 GPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_gpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_GPU_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_GPU_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_GPU_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_GPU_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_GPU_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_GPU_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET,
+};
+
+/* Thresholds and limits for DRA752 MPU temperature sensor */
+static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
+ .tshut_hot = DRA752_MPU_TSHUT_HOT,
+ .tshut_cold = DRA752_MPU_TSHUT_COLD,
+ .t_hot = DRA752_MPU_T_HOT,
+ .t_cold = DRA752_MPU_T_COLD,
+ .min_freq = DRA752_MPU_MIN_FREQ,
+ .max_freq = DRA752_MPU_MAX_FREQ,
+ .max_temp = DRA752_MPU_MAX_TEMP,
+ .min_temp = DRA752_MPU_MIN_TEMP,
+ .hyst_val = DRA752_MPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 GPU temperature sensor */
+static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
+ .tshut_hot = DRA752_GPU_TSHUT_HOT,
+ .tshut_cold = DRA752_GPU_TSHUT_COLD,
+ .t_hot = DRA752_GPU_T_HOT,
+ .t_cold = DRA752_GPU_T_COLD,
+ .min_freq = DRA752_GPU_MIN_FREQ,
+ .max_freq = DRA752_GPU_MAX_FREQ,
+ .max_temp = DRA752_GPU_MAX_TEMP,
+ .min_temp = DRA752_GPU_MIN_TEMP,
+ .hyst_val = DRA752_GPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 CORE temperature sensor */
+static struct temp_sensor_data dra752_core_temp_sensor_data = {
+ .tshut_hot = DRA752_CORE_TSHUT_HOT,
+ .tshut_cold = DRA752_CORE_TSHUT_COLD,
+ .t_hot = DRA752_CORE_T_HOT,
+ .t_cold = DRA752_CORE_T_COLD,
+ .min_freq = DRA752_CORE_MIN_FREQ,
+ .max_freq = DRA752_CORE_MAX_FREQ,
+ .max_temp = DRA752_CORE_MAX_TEMP,
+ .min_temp = DRA752_CORE_MIN_TEMP,
+ .hyst_val = DRA752_CORE_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
+static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
+ .tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
+ .tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
+ .t_hot = DRA752_DSPEVE_T_HOT,
+ .t_cold = DRA752_DSPEVE_T_COLD,
+ .min_freq = DRA752_DSPEVE_MIN_FREQ,
+ .max_freq = DRA752_DSPEVE_MAX_FREQ,
+ .max_temp = DRA752_DSPEVE_MAX_TEMP,
+ .min_temp = DRA752_DSPEVE_MIN_TEMP,
+ .hyst_val = DRA752_DSPEVE_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 IVA temperature sensor */
+static struct temp_sensor_data dra752_iva_temp_sensor_data = {
+ .tshut_hot = DRA752_IVA_TSHUT_HOT,
+ .tshut_cold = DRA752_IVA_TSHUT_COLD,
+ .t_hot = DRA752_IVA_T_HOT,
+ .t_cold = DRA752_IVA_T_COLD,
+ .min_freq = DRA752_IVA_MIN_FREQ,
+ .max_freq = DRA752_IVA_MAX_FREQ,
+ .max_temp = DRA752_IVA_MAX_TEMP,
+ .min_temp = DRA752_IVA_MIN_TEMP,
+ .hyst_val = DRA752_IVA_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/*
+ * DRA752 : Temperature values in milli degree celsius
+ * ADC code values from 540 to 945
+ */
+static
+int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
+ /* Index 540 - 549 */
+ -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
+ -37800,
+ /* Index 550 - 559 */
+ -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
+ -33400,
+ /* Index 560 - 569 */
+ -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
+ -29400,
+ /* Index 570 - 579 */
+ -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
+ -25000,
+ /* Index 580 - 589 */
+ -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21800, -21400,
+ -21000,
+ /* Index 590 - 599 */
+ -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
+ -16600,
+ /* Index 600 - 609 */
+ -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
+ -12500,
+ /* Index 610 - 619 */
+ -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
+ -8200,
+ /* Index 620 - 629 */
+ -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500,
+ -3900,
+ /* Index 630 - 639 */
+ -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200,
+ 200,
+ /* Index 640 - 649 */
+ 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900,
+ 4500,
+ /* Index 650 - 659 */
+ 5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200,
+ 8600,
+ /* Index 660 - 669 */
+ 9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200,
+ 12700,
+ /* Index 670 - 679 */
+ 13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600,
+ 17000,
+ /* Index 680 - 689 */
+ 17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600,
+ 21000,
+ /* Index 690 - 699 */
+ 21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000,
+ 25400,
+ /* Index 700 - 709 */
+ 25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000,
+ 29400,
+ /* Index 710 - 719 */
+ 29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400,
+ 33800,
+ /* Index 720 - 729 */
+ 34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400,
+ 37800,
+ /* Index 730 - 739 */
+ 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400,
+ 41800,
+ /* Index 740 - 749 */
+ 42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800,
+ 46200,
+ /* Index 750 - 759 */
+ 46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800,
+ 50200,
+ /* Index 760 - 769 */
+ 50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800,
+ 54200,
+ /* Index 770 - 779 */
+ 54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200,
+ 58600,
+ /* Index 780 - 789 */
+ 59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200,
+ 62600,
+ /* Index 790 - 799 */
+ 63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200,
+ 66600,
+ /* Index 800 - 809 */
+ 67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200,
+ 70600,
+ /* Index 810 - 819 */
+ 71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600,
+ 75000,
+ /* Index 820 - 829 */
+ 75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600,
+ 79000,
+ /* Index 830 - 839 */
+ 79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600,
+ 83000,
+ /* Index 840 - 849 */
+ 83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600,
+ 87000,
+ /* Index 850 - 859 */
+ 87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600,
+ 91000,
+ /* Index 860 - 869 */
+ 91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600,
+ 95000,
+ /* Index 870 - 879 */
+ 95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000,
+ 99400,
+ /* Index 880 - 889 */
+ 99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
+ 103400,
+ /* Index 890 - 899 */
+ 103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
+ 107400,
+ /* Index 900 - 909 */
+ 107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
+ 111400,
+ /* Index 910 - 919 */
+ 111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
+ 115400,
+ /* Index 920 - 929 */
+ 115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
+ 119400,
+ /* Index 930 - 939 */
+ 119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
+ 123400,
+ /* Index 940 - 945 */
+ 123800, 124200, 124600, 124900, 125000, 125000,
+};
+
+/* DRA752 data */
+const struct ti_bandgap_data dra752_data = {
+ .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+ TI_BANDGAP_FEATURE_FREEZE_BIT |
+ TI_BANDGAP_FEATURE_TALERT |
+ TI_BANDGAP_FEATURE_COUNTER_DELAY |
+ TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+ .fclock_name = "l3instr_ts_gclk_div",
+ .div_ck_name = "l3instr_ts_gclk_div",
+ .conv_table = dra752_adc_to_temp,
+ .adc_start_val = DRA752_ADC_START_VALUE,
+ .adc_end_val = DRA752_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+ .sensors = {
+ {
+ .registers = &dra752_mpu_temp_sensor_registers,
+ .ts_data = &dra752_mpu_temp_sensor_data,
+ .domain = "cpu",
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_gpu_temp_sensor_registers,
+ .ts_data = &dra752_gpu_temp_sensor_data,
+ .domain = "gpu",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_core_temp_sensor_registers,
+ .ts_data = &dra752_core_temp_sensor_data,
+ .domain = "core",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_dspeve_temp_sensor_registers,
+ .ts_data = &dra752_dspeve_temp_sensor_data,
+ .domain = "dspeve",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_iva_temp_sensor_registers,
+ .ts_data = &dra752_iva_temp_sensor_data,
+ .domain = "iva",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ },
+ .sensor_count = 5,
+};
diff --git a/drivers/staging/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
index d255d33da9eb..d255d33da9eb 100644
--- a/drivers/staging/ti-soc-thermal/omap4-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
diff --git a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
index 6f2de3a3356d..6f2de3a3356d 100644
--- a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
diff --git a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
index eff0c80fd4af..eff0c80fd4af 100644
--- a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
diff --git a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
index 400b55dffadd..400b55dffadd 100644
--- a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
index f20c1cfe9800..9dfd47196e63 100644
--- a/drivers/staging/ti-soc-thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
@@ -38,6 +38,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
#include <linux/io.h>
#include "ti-bandgap.h"
@@ -469,7 +470,7 @@ static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
{
int ret = 0;
- if (IS_ERR_OR_NULL(bgp)) {
+ if (!bgp || IS_ERR(bgp)) {
pr_err("%s: invalid bandgap pointer\n", __func__);
ret = -EINVAL;
goto exit;
@@ -992,9 +993,12 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
goto exit;
}
+ spin_lock(&bgp->lock);
+
tsr = bgp->conf->sensors[id].registers;
/* Freeze and read the last 2 valid readings */
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
reg1 = tsr->ctrl_dtemp_1;
reg2 = tsr->ctrl_dtemp_2;
@@ -1008,22 +1012,25 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
/* Convert from adc values to mCelsius temperature */
ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
if (ret)
- goto exit;
+ goto unfreeze;
ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
if (ret)
- goto exit;
+ goto unfreeze;
/* Fetch the update interval */
ret = ti_bandgap_read_update_interval(bgp, id, &interval);
if (ret || !interval)
- goto exit;
+ goto unfreeze;
*trend = (t1 - t2) / interval;
dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
t1, t2, *trend);
+unfreeze:
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
+ spin_unlock(&bgp->lock);
exit:
return ret;
}
@@ -1123,7 +1130,6 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
const struct of_device_id *of_id;
struct ti_bandgap *bgp;
struct resource *res;
- u32 prop;
int i;
/* just for the sake */
@@ -1167,11 +1173,7 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
} while (res);
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
- if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
- dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
- return ERR_PTR(-EINVAL);
- }
- bgp->tshut_gpio = prop;
+ bgp->tshut_gpio = of_get_gpio(node, 0);
if (!gpio_is_valid(bgp->tshut_gpio)) {
dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
bgp->tshut_gpio);
@@ -1191,7 +1193,7 @@ int ti_bandgap_probe(struct platform_device *pdev)
int clk_rate, ret = 0, i;
bgp = ti_bandgap_build(pdev);
- if (IS_ERR_OR_NULL(bgp)) {
+ if (IS_ERR(bgp)) {
dev_err(&pdev->dev, "failed to fetch platform data\n");
return PTR_ERR(bgp);
}
@@ -1207,17 +1209,19 @@ int ti_bandgap_probe(struct platform_device *pdev)
}
bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
- ret = IS_ERR_OR_NULL(bgp->fclock);
+ ret = IS_ERR(bgp->fclock);
if (ret) {
dev_err(&pdev->dev, "failed to request fclock reference\n");
+ ret = PTR_ERR(bgp->fclock);
goto free_irqs;
}
bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);
- ret = IS_ERR_OR_NULL(bgp->div_clk);
+ ret = IS_ERR(bgp->div_clk);
if (ret) {
dev_err(&pdev->dev,
"failed to request div_ts_ck clock ref\n");
+ ret = PTR_ERR(bgp->div_clk);
goto free_irqs;
}
@@ -1523,6 +1527,12 @@ static const struct of_device_id of_ti_bandgap_match[] = {
.data = (void *)&omap5430_data,
},
#endif
+#ifdef CONFIG_DRA752_THERMAL
+ {
+ .compatible = "ti,dra752-bandgap",
+ .data = (void *)&dra752_data,
+ },
+#endif
/* Sentinel */
{ },
};
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
index 5f4794abf583..b3adf72f252d 100644
--- a/drivers/staging/ti-soc-thermal/ti-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
@@ -400,4 +400,9 @@ extern const struct ti_bandgap_data omap5430_data;
#define omap5430_data NULL
#endif
+#ifdef CONFIG_DRA752_THERMAL
+extern const struct ti_bandgap_data dra752_data;
+#else
+#define dra752_data NULL
+#endif
#endif
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 8e67ebf98404..4c5f55c37349 100644
--- a/drivers/staging/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -101,7 +101,7 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
pcb_tz = data->pcb_tz;
/* In case pcb zone is available, use the extrapolation rule with it */
- if (!IS_ERR_OR_NULL(pcb_tz)) {
+ if (!IS_ERR(pcb_tz)) {
ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
if (!ret) {
tmp -= pcb_temp; /* got a valid PCB temp */
@@ -124,7 +124,7 @@ static int ti_thermal_bind(struct thermal_zone_device *thermal,
struct ti_thermal_data *data = thermal->devdata;
int id;
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
return -ENODEV;
/* check if this is the cooling device we registered */
@@ -146,7 +146,7 @@ static int ti_thermal_unbind(struct thermal_zone_device *thermal,
{
struct ti_thermal_data *data = thermal->devdata;
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
return -ENODEV;
/* check if this is the cooling device we registered */
@@ -282,6 +282,7 @@ static struct ti_thermal_data
data->sensor_id = id;
data->bgp = bgp;
data->mode = THERMAL_DEVICE_ENABLED;
+ /* pcb_tz will be either valid or PTR_ERR() */
data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
INIT_WORK(&data->thermal_wq, ti_thermal_work);
@@ -295,7 +296,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
data = ti_bandgap_get_sensor_data(bgp, id);
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
data = ti_thermal_build_data(bgp, id);
if (!data)
@@ -306,7 +307,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
NULL, FAST_TEMP_MONITORING_RATE,
FAST_TEMP_MONITORING_RATE);
- if (IS_ERR_OR_NULL(data->ti_thermal)) {
+ if (IS_ERR(data->ti_thermal)) {
dev_err(bgp->dev, "thermal zone device is NULL\n");
return PTR_ERR(data->ti_thermal);
}
@@ -343,7 +344,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
struct ti_thermal_data *data;
data = ti_bandgap_get_sensor_data(bgp, id);
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
data = ti_thermal_build_data(bgp, id);
if (!data)
@@ -356,7 +357,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
/* Register cooling device */
data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
- if (IS_ERR_OR_NULL(data->cool_dev)) {
+ if (IS_ERR(data->cool_dev)) {
dev_err(bgp->dev,
"Failed to register cpufreq cooling device\n");
return PTR_ERR(data->cool_dev);
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h
index 5055777727cc..f8b7ffea6194 100644
--- a/drivers/staging/ti-soc-thermal/ti-thermal.h
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal.h
@@ -38,6 +38,9 @@
#define OMAP_GRADIENT_SLOPE_5430_GPU 117
#define OMAP_GRADIENT_CONST_5430_GPU -2992
+#define DRA752_GRADIENT_SLOPE 0
+#define DRA752_GRADIENT_CONST 2000
+
/* PCB sensor calculation constants */
#define OMAP_GRADIENT_SLOPE_W_PCB_4430 0
#define OMAP_GRADIENT_CONST_W_PCB_4430 20000
@@ -51,6 +54,9 @@
#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 464
#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU -5102
+#define DRA752_GRADIENT_SLOPE_W_PCB 0
+#define DRA752_GRADIENT_CONST_W_PCB 2000
+
/* trip points of interest in milicelsius (at hotspot level) */
#define OMAP_TRIP_COLD 100000
#define OMAP_TRIP_HOT 110000
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
new file mode 100644
index 000000000000..5de56f671a9d
--- /dev/null
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -0,0 +1,642 @@
+/*
+ * x86_pkg_temp_thermal driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/thermal.h>
+#include <linux/debugfs.h>
+#include <asm/cpu_device_id.h>
+#include <asm/mce.h>
+
+/*
+* Rate control delay: Idea is to introduce denounce effect
+* This should be long enough to avoid reduce events, when
+* threshold is set to a temperature, which is constantly
+* violated, but at the short enough to take any action.
+* The action can be remove threshold or change it to next
+* interesting setting. Based on experiments, in around
+* every 5 seconds under load will give us a significant
+* temperature change.
+*/
+#define PKG_TEMP_THERMAL_NOTIFY_DELAY 5000
+static int notify_delay_ms = PKG_TEMP_THERMAL_NOTIFY_DELAY;
+module_param(notify_delay_ms, int, 0644);
+MODULE_PARM_DESC(notify_delay_ms,
+ "User space notification delay in milli seconds.");
+
+/* Number of trip points in thermal zone. Currently it can't
+* be more than 2. MSR can allow setting and getting notifications
+* for only 2 thresholds. This define enforces this, if there
+* is some wrong values returned by cpuid for number of thresholds.
+*/
+#define MAX_NUMBER_OF_TRIPS 2
+
+struct phy_dev_entry {
+ struct list_head list;
+ u16 phys_proc_id;
+ u16 first_cpu;
+ u32 tj_max;
+ int ref_cnt;
+ u32 start_pkg_therm_low;
+ u32 start_pkg_therm_high;
+ struct thermal_zone_device *tzone;
+};
+
+/* List maintaining number of package instances */
+static LIST_HEAD(phy_dev_list);
+static DEFINE_MUTEX(phy_dev_list_mutex);
+
+/* Interrupt to work function schedule queue */
+static DEFINE_PER_CPU(struct delayed_work, pkg_temp_thermal_threshold_work);
+
+/* To track if the work is already scheduled on a package */
+static u8 *pkg_work_scheduled;
+
+/* Spin lock to prevent races with pkg_work_scheduled */
+static spinlock_t pkg_work_lock;
+static u16 max_phy_id;
+
+/* Debug counters to show using debugfs */
+static struct dentry *debugfs;
+static unsigned int pkg_interrupt_cnt;
+static unsigned int pkg_work_cnt;
+
+static int pkg_temp_debugfs_init(void)
+{
+ struct dentry *d;
+
+ debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
+ if (!debugfs)
+ return -ENOENT;
+
+ d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
+ (u32 *)&pkg_interrupt_cnt);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
+ (u32 *)&pkg_work_cnt);
+ if (!d)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(debugfs);
+ return -ENOENT;
+}
+
+static struct phy_dev_entry
+ *pkg_temp_thermal_get_phy_entry(unsigned int cpu)
+{
+ u16 phys_proc_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phy_ptr;
+
+ mutex_lock(&phy_dev_list_mutex);
+
+ list_for_each_entry(phy_ptr, &phy_dev_list, list)
+ if (phy_ptr->phys_proc_id == phys_proc_id) {
+ mutex_unlock(&phy_dev_list_mutex);
+ return phy_ptr;
+ }
+
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return NULL;
+}
+
+/*
+* tj-max is is interesting because threshold is set relative to this
+* temperature.
+*/
+static int get_tj_max(int cpu, u32 *tj_max)
+{
+ u32 eax, edx;
+ u32 val;
+ int err;
+
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (err)
+ goto err_ret;
+ else {
+ val = (eax >> 16) & 0xff;
+ if (val)
+ *tj_max = val * 1000;
+ else {
+ err = -EINVAL;
+ goto err_ret;
+ }
+ }
+
+ return 0;
+err_ret:
+ *tj_max = 0;
+ return err;
+}
+
+static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+{
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+
+ phy_dev_entry = tzd->devdata;
+ rdmsr_on_cpu(phy_dev_entry->first_cpu, MSR_IA32_PACKAGE_THERM_STATUS,
+ &eax, &edx);
+ if (eax & 0x80000000) {
+ *temp = phy_dev_entry->tj_max -
+ ((eax >> 16) & 0x7f) * 1000;
+ pr_debug("sys_get_curr_temp %ld\n", *temp);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+ int trip, unsigned long *temp)
+{
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+ u32 mask, shift;
+ unsigned long thres_reg_value;
+ int ret;
+
+ if (trip >= MAX_NUMBER_OF_TRIPS)
+ return -EINVAL;
+
+ phy_dev_entry = tzd->devdata;
+
+ if (trip) {
+ mask = THERM_MASK_THRESHOLD1;
+ shift = THERM_SHIFT_THRESHOLD1;
+ } else {
+ mask = THERM_MASK_THRESHOLD0;
+ shift = THERM_SHIFT_THRESHOLD0;
+ }
+
+ ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx);
+ if (ret < 0)
+ return -EINVAL;
+
+ thres_reg_value = (eax & mask) >> shift;
+ if (thres_reg_value)
+ *temp = phy_dev_entry->tj_max - thres_reg_value * 1000;
+ else
+ *temp = 0;
+ pr_debug("sys_get_trip_temp %ld\n", *temp);
+
+ return 0;
+}
+
+int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+ unsigned long temp)
+{
+ u32 l, h;
+ struct phy_dev_entry *phy_dev_entry;
+ u32 mask, shift, intr;
+ int ret;
+
+ phy_dev_entry = tzd->devdata;
+
+ if (trip >= MAX_NUMBER_OF_TRIPS || temp >= phy_dev_entry->tj_max)
+ return -EINVAL;
+
+ ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ &l, &h);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (trip) {
+ mask = THERM_MASK_THRESHOLD1;
+ shift = THERM_SHIFT_THRESHOLD1;
+ intr = THERM_INT_THRESHOLD1_ENABLE;
+ } else {
+ mask = THERM_MASK_THRESHOLD0;
+ shift = THERM_SHIFT_THRESHOLD0;
+ intr = THERM_INT_THRESHOLD0_ENABLE;
+ }
+ l &= ~mask;
+ /*
+ * When users space sets a trip temperature == 0, which is indication
+ * that, it is no longer interested in receiving notifications.
+ */
+ if (!temp)
+ l &= ~intr;
+ else {
+ l |= (phy_dev_entry->tj_max - temp)/1000 << shift;
+ l |= intr;
+ }
+
+ return wrmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l, h);
+}
+
+static int sys_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_type *type)
+{
+
+ *type = THERMAL_TRIP_PASSIVE;
+
+ return 0;
+}
+
+/* Thermal zone callback registry */
+static struct thermal_zone_device_ops tzone_ops = {
+ .get_temp = sys_get_curr_temp,
+ .get_trip_temp = sys_get_trip_temp,
+ .get_trip_type = sys_get_trip_type,
+ .set_trip_temp = sys_set_trip_temp,
+};
+
+static bool pkg_temp_thermal_platform_thermal_rate_control(void)
+{
+ return true;
+}
+
+/* Enable threshold interrupt on local package/cpu */
+static inline void enable_pkg_thres_interrupt(void)
+{
+ u32 l, h;
+ u8 thres_0, thres_1;
+
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ /* only enable/disable if it had valid threshold value */
+ thres_0 = (l & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0;
+ thres_1 = (l & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1;
+ if (thres_0)
+ l |= THERM_INT_THRESHOLD0_ENABLE;
+ if (thres_1)
+ l |= THERM_INT_THRESHOLD1_ENABLE;
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
+/* Disable threshold interrupt on local package/cpu */
+static inline void disable_pkg_thres_interrupt(void)
+{
+ u32 l, h;
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l & (~THERM_INT_THRESHOLD0_ENABLE) &
+ (~THERM_INT_THRESHOLD1_ENABLE), h);
+}
+
+static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
+{
+ __u64 msr_val;
+ int cpu = smp_processor_id();
+ int phy_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+ bool notify = false;
+
+ if (!phdev)
+ return;
+
+ spin_lock(&pkg_work_lock);
+ ++pkg_work_cnt;
+ if (unlikely(phy_id > max_phy_id)) {
+ spin_unlock(&pkg_work_lock);
+ return;
+ }
+ pkg_work_scheduled[phy_id] = 0;
+ spin_unlock(&pkg_work_lock);
+
+ enable_pkg_thres_interrupt();
+ rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ if (msr_val & THERM_LOG_THRESHOLD0) {
+ wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+ msr_val & ~THERM_LOG_THRESHOLD0);
+ notify = true;
+ }
+ if (msr_val & THERM_LOG_THRESHOLD1) {
+ wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+ msr_val & ~THERM_LOG_THRESHOLD1);
+ notify = true;
+ }
+ if (notify) {
+ pr_debug("thermal_zone_device_update\n");
+ thermal_zone_device_update(phdev->tzone);
+ }
+}
+
+static int pkg_temp_thermal_platform_thermal_notify(__u64 msr_val)
+{
+ unsigned long flags;
+ int cpu = smp_processor_id();
+ int phy_id = topology_physical_package_id(cpu);
+
+ /*
+ * When a package is in interrupted state, all CPU's in that package
+ * are in the same interrupt state. So scheduling on any one CPU in
+ * the package is enough and simply return for others.
+ */
+ spin_lock_irqsave(&pkg_work_lock, flags);
+ ++pkg_interrupt_cnt;
+ if (unlikely(phy_id > max_phy_id) || unlikely(!pkg_work_scheduled) ||
+ pkg_work_scheduled[phy_id]) {
+ disable_pkg_thres_interrupt();
+ spin_unlock_irqrestore(&pkg_work_lock, flags);
+ return -EINVAL;
+ }
+ pkg_work_scheduled[phy_id] = 1;
+ spin_unlock_irqrestore(&pkg_work_lock, flags);
+
+ disable_pkg_thres_interrupt();
+ schedule_delayed_work_on(cpu,
+ &per_cpu(pkg_temp_thermal_threshold_work, cpu),
+ msecs_to_jiffies(notify_delay_ms));
+ return 0;
+}
+
+static int find_siblings_cpu(int cpu)
+{
+ int i;
+ int id = topology_physical_package_id(cpu);
+
+ for_each_online_cpu(i)
+ if (i != cpu && topology_physical_package_id(i) == id)
+ return i;
+
+ return 0;
+}
+
+static int pkg_temp_thermal_device_add(unsigned int cpu)
+{
+ int err;
+ u32 tj_max;
+ struct phy_dev_entry *phy_dev_entry;
+ char buffer[30];
+ int thres_count;
+ u32 eax, ebx, ecx, edx;
+
+ cpuid(6, &eax, &ebx, &ecx, &edx);
+ thres_count = ebx & 0x07;
+ if (!thres_count)
+ return -ENODEV;
+
+ thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
+
+ err = get_tj_max(cpu, &tj_max);
+ if (err)
+ goto err_ret;
+
+ mutex_lock(&phy_dev_list_mutex);
+
+ phy_dev_entry = kzalloc(sizeof(*phy_dev_entry), GFP_KERNEL);
+ if (!phy_dev_entry) {
+ err = -ENOMEM;
+ goto err_ret_unlock;
+ }
+
+ spin_lock(&pkg_work_lock);
+ if (topology_physical_package_id(cpu) > max_phy_id)
+ max_phy_id = topology_physical_package_id(cpu);
+ pkg_work_scheduled = krealloc(pkg_work_scheduled,
+ (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
+ if (!pkg_work_scheduled) {
+ spin_unlock(&pkg_work_lock);
+ err = -ENOMEM;
+ goto err_ret_free;
+ }
+ pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
+ spin_unlock(&pkg_work_lock);
+
+ phy_dev_entry->phys_proc_id = topology_physical_package_id(cpu);
+ phy_dev_entry->first_cpu = cpu;
+ phy_dev_entry->tj_max = tj_max;
+ phy_dev_entry->ref_cnt = 1;
+ snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
+ phy_dev_entry->phys_proc_id);
+ phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+ thres_count,
+ (thres_count == MAX_NUMBER_OF_TRIPS) ?
+ 0x03 : 0x01,
+ phy_dev_entry, &tzone_ops, NULL, 0, 0);
+ if (IS_ERR(phy_dev_entry->tzone)) {
+ err = PTR_ERR(phy_dev_entry->tzone);
+ goto err_ret_free;
+ }
+ /* Store MSR value for package thermal interrupt, to restore at exit */
+ rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ &phy_dev_entry->start_pkg_therm_low,
+ &phy_dev_entry->start_pkg_therm_high);
+
+ list_add_tail(&phy_dev_entry->list, &phy_dev_list);
+ pr_debug("pkg_temp_thermal_device_add :phy_id %d cpu %d\n",
+ phy_dev_entry->phys_proc_id, cpu);
+
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return 0;
+
+err_ret_free:
+ kfree(phy_dev_entry);
+err_ret_unlock:
+ mutex_unlock(&phy_dev_list_mutex);
+
+err_ret:
+ return err;
+}
+
+static int pkg_temp_thermal_device_remove(unsigned int cpu)
+{
+ struct phy_dev_entry *n;
+ u16 phys_proc_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phdev =
+ pkg_temp_thermal_get_phy_entry(cpu);
+
+ if (!phdev)
+ return -ENODEV;
+
+ mutex_lock(&phy_dev_list_mutex);
+ /* If we are loosing the first cpu for this package, we need change */
+ if (phdev->first_cpu == cpu) {
+ phdev->first_cpu = find_siblings_cpu(cpu);
+ pr_debug("thermal_device_remove: first cpu switched %d\n",
+ phdev->first_cpu);
+ }
+ /*
+ * It is possible that no siblings left as this was the last cpu
+ * going offline. We don't need to worry about this assignment
+ * as the phydev entry will be removed in this case and
+ * thermal zone is removed.
+ */
+ --phdev->ref_cnt;
+ pr_debug("thermal_device_remove: pkg: %d cpu %d ref_cnt %d\n",
+ phys_proc_id, cpu, phdev->ref_cnt);
+ if (!phdev->ref_cnt)
+ list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+ if (phdev->phys_proc_id == phys_proc_id) {
+ thermal_zone_device_unregister(phdev->tzone);
+ list_del(&phdev->list);
+ kfree(phdev);
+ break;
+ }
+ }
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return 0;
+}
+
+static int get_core_online(unsigned int cpu)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+
+ /* Check if there is already an instance for this package */
+ if (!phdev) {
+ if (!cpu_has(c, X86_FEATURE_DTHERM) &&
+ !cpu_has(c, X86_FEATURE_PTS))
+ return -ENODEV;
+ if (pkg_temp_thermal_device_add(cpu))
+ return -ENODEV;
+ } else {
+ mutex_lock(&phy_dev_list_mutex);
+ ++phdev->ref_cnt;
+ pr_debug("get_core_online: cpu %d ref_cnt %d\n",
+ cpu, phdev->ref_cnt);
+ mutex_unlock(&phy_dev_list_mutex);
+ }
+ INIT_DELAYED_WORK(&per_cpu(pkg_temp_thermal_threshold_work, cpu),
+ pkg_temp_thermal_threshold_work_fn);
+
+ pr_debug("get_core_online: cpu %d successful\n", cpu);
+
+ return 0;
+}
+
+static void put_core_offline(unsigned int cpu)
+{
+ if (!pkg_temp_thermal_device_remove(cpu))
+ cancel_delayed_work_sync(
+ &per_cpu(pkg_temp_thermal_threshold_work, cpu));
+
+ pr_debug("put_core_offline: cpu %d\n", cpu);
+}
+
+static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ get_core_online(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ put_core_offline(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block pkg_temp_thermal_notifier __refdata = {
+ .notifier_call = pkg_temp_thermal_cpu_callback,
+};
+
+static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
+ { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
+
+static int __init pkg_temp_thermal_init(void)
+{
+ int i;
+
+ if (!x86_match_cpu(pkg_temp_thermal_ids))
+ return -ENODEV;
+
+ spin_lock_init(&pkg_work_lock);
+ platform_thermal_package_notify =
+ pkg_temp_thermal_platform_thermal_notify;
+ platform_thermal_package_rate_control =
+ pkg_temp_thermal_platform_thermal_rate_control;
+
+ get_online_cpus();
+ for_each_online_cpu(i)
+ if (get_core_online(i))
+ goto err_ret;
+ register_hotcpu_notifier(&pkg_temp_thermal_notifier);
+ put_online_cpus();
+
+ pkg_temp_debugfs_init(); /* Don't care if fails */
+
+ return 0;
+
+err_ret:
+ get_online_cpus();
+ for_each_online_cpu(i)
+ put_core_offline(i);
+ put_online_cpus();
+ kfree(pkg_work_scheduled);
+ platform_thermal_package_notify = NULL;
+ platform_thermal_package_rate_control = NULL;
+
+ return -ENODEV;
+}
+
+static void __exit pkg_temp_thermal_exit(void)
+{
+ struct phy_dev_entry *phdev, *n;
+ int i;
+
+ get_online_cpus();
+ unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
+ mutex_lock(&phy_dev_list_mutex);
+ list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+ /* Retore old MSR value for package thermal interrupt */
+ wrmsr_on_cpu(phdev->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ phdev->start_pkg_therm_low,
+ phdev->start_pkg_therm_high);
+ thermal_zone_device_unregister(phdev->tzone);
+ list_del(&phdev->list);
+ kfree(phdev);
+ }
+ mutex_unlock(&phy_dev_list_mutex);
+ platform_thermal_package_notify = NULL;
+ platform_thermal_package_rate_control = NULL;
+ for_each_online_cpu(i)
+ cancel_delayed_work_sync(
+ &per_cpu(pkg_temp_thermal_threshold_work, i));
+ put_online_cpus();
+
+ kfree(pkg_work_scheduled);
+
+ debugfs_remove_recursive(debugfs);
+}
+
+module_init(pkg_temp_thermal_init)
+module_exit(pkg_temp_thermal_exit)
+
+MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index d07b6af3a937..76a8daadff47 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,8 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <asm/byteorder.h>
+
#include "8250.h"
/* Offsets for the DesignWare specific registers */
@@ -57,6 +59,7 @@ struct dw8250_data {
int last_lcr;
int line;
struct clk *clk;
+ u8 usr_reg;
};
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
@@ -77,6 +80,13 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
return readb(p->membase + offset);
}
+/* Read Back (rb) version to ensure register access ording. */
+static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value)
+{
+ dw8250_serial_out(p, offset, value);
+ dw8250_serial_in(p, UART_LCR);
+}
+
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -104,7 +114,7 @@ static int dw8250_handle_irq(struct uart_port *p)
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR and write the LCR again. */
- (void)p->serial_in(p, DW_UART_USR);
+ (void)p->serial_in(p, d->usr_reg);
p->serial_out(p, UART_LCR, d->last_lcr);
return 1;
@@ -125,12 +135,60 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
pm_runtime_put_sync_suspend(port->dev);
}
-static int dw8250_probe_of(struct uart_port *p)
+static void dw8250_setup_port(struct uart_8250_port *up)
+{
+ struct uart_port *p = &up->port;
+ u32 reg = readl(p->membase + DW_UART_UCV);
+
+ /*
+ * If the Component Version Register returns zero, we know that
+ * ADDITIONAL_FEATURES are not enabled. No need to go any further.
+ */
+ if (!reg)
+ return;
+
+ dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+
+ reg = readl(p->membase + DW_UART_CPR);
+ if (!reg)
+ return;
+
+ /* Select the type based on fifo */
+ if (reg & DW_UART_CPR_FIFO_MODE) {
+ p->type = PORT_16550A;
+ p->flags |= UPF_FIXED_TYPE;
+ p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
+ up->tx_loadsz = p->fifosize;
+ up->capabilities = UART_CAP_FIFO;
+ }
+
+ if (reg & DW_UART_CPR_AFCE_MODE)
+ up->capabilities |= UART_CAP_AFE;
+}
+
+static int dw8250_probe_of(struct uart_port *p,
+ struct dw8250_data *data)
{
struct device_node *np = p->dev->of_node;
u32 val;
-
- if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ bool has_ucv = true;
+
+ if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
+#ifdef __BIG_ENDIAN
+ /*
+ * Low order bits of these 64-bit registers, when
+ * accessed as a byte, are 7 bytes further down in the
+ * address space in big endian mode.
+ */
+ p->membase += 7;
+#endif
+ p->serial_out = dw8250_serial_out_rb;
+ p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ p->type = PORT_OCTEON;
+ data->usr_reg = 0x27;
+ has_ucv = false;
+ } else if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
@@ -144,6 +202,8 @@ static int dw8250_probe_of(struct uart_port *p)
return -EINVAL;
}
}
+ if (has_ucv)
+ dw8250_setup_port(container_of(p, struct uart_8250_port, port));
if (!of_property_read_u32(np, "reg-shift", &val))
p->regshift = val;
@@ -168,6 +228,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up)
const struct acpi_device_id *id;
struct uart_port *p = &up->port;
+ dw8250_setup_port(up);
+
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
if (!id)
return -ENODEV;
@@ -196,38 +258,6 @@ static inline int dw8250_probe_acpi(struct uart_8250_port *up)
}
#endif /* CONFIG_ACPI */
-static void dw8250_setup_port(struct uart_8250_port *up)
-{
- struct uart_port *p = &up->port;
- u32 reg = readl(p->membase + DW_UART_UCV);
-
- /*
- * If the Component Version Register returns zero, we know that
- * ADDITIONAL_FEATURES are not enabled. No need to go any further.
- */
- if (!reg)
- return;
-
- dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
- (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
-
- reg = readl(p->membase + DW_UART_CPR);
- if (!reg)
- return;
-
- /* Select the type based on fifo */
- if (reg & DW_UART_CPR_FIFO_MODE) {
- p->type = PORT_16550A;
- p->flags |= UPF_FIXED_TYPE;
- p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
- up->tx_loadsz = p->fifosize;
- up->capabilities = UART_CAP_FIFO;
- }
-
- if (reg & DW_UART_CPR_AFCE_MODE)
- up->capabilities |= UART_CAP_AFE;
-}
-
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
@@ -259,6 +289,7 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->usr_reg = DW_UART_USR;
data->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(data->clk)) {
clk_prepare_enable(data->clk);
@@ -270,10 +301,8 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.serial_out = dw8250_serial_out;
uart.port.private_data = data;
- dw8250_setup_port(&uart);
-
if (pdev->dev.of_node) {
- err = dw8250_probe_of(&uart.port);
+ err = dw8250_probe_of(&uart.port, data);
if (err)
return err;
} else if (ACPI_HANDLE(&pdev->dev)) {
@@ -362,6 +391,7 @@ static const struct dev_pm_ops dw8250_pm_ops = {
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" },
+ { .compatible = "cavium,octeon-3860-uart" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index 5f91c7a59946..e2a1f50bd93c 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -406,7 +406,7 @@ uvc_register_video(struct uvc_device *uvc)
if (video == NULL)
return -ENOMEM;
- video->parent = &cdev->gadget->dev;
+ video->v4l2_dev = &uvc->v4l2_dev;
video->fops = &uvc_v4l2_fops;
video->release = video_device_release;
strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
@@ -563,6 +563,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
INFO(cdev, "uvc_function_unbind\n");
video_unregister_device(uvc->vdev);
+ v4l2_device_unregister(&uvc->v4l2_dev);
uvc->control_ep->driver_data = NULL;
uvc->video.ep->driver_data = NULL;
@@ -690,6 +691,11 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
if ((ret = usb_function_deactivate(f)) < 0)
goto error;
+ if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
+ printk(KERN_INFO "v4l2_device_register failed\n");
+ goto error;
+ }
+
/* Initialise video. */
ret = uvc_video_init(&uvc->video);
if (ret < 0)
@@ -705,6 +711,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
error:
+ v4l2_device_unregister(&uvc->v4l2_dev);
if (uvc->vdev)
video_device_release(uvc->vdev);
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index 7cacd6ae818e..0ff33396eef3 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -1467,9 +1467,8 @@ static int usbg_get_cmd_state(struct se_cmd *se_cmd)
return 0;
}
-static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
{
- return 0;
}
static const char *usbg_check_wwn(const char *name)
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index 817e9e19cecf..7a9111de8054 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -57,6 +57,7 @@ struct uvc_event
#include <linux/videodev2.h>
#include <linux/version.h>
#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
#include "uvc_queue.h"
@@ -145,6 +146,7 @@ enum uvc_state
struct uvc_device
{
struct video_device *vdev;
+ struct v4l2_device v4l2_dev;
enum uvc_state state;
struct usb_function func;
struct uvc_video video;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2817013bceb1..4263d011392c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -283,7 +283,7 @@ config USB_EHCI_HCD_PLATFORM
config USB_OCTEON_EHCI
bool "Octeon on-chip EHCI support"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
default n
select USB_EHCI_BIG_ENDIAN_MMIO
help
@@ -488,7 +488,7 @@ config USB_OHCI_HCD_PLATFORM
config USB_OCTEON_OHCI
bool "Octeon on-chip OHCI support"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
default USB_OCTEON_EHCI
select USB_OHCI_BIG_ENDIAN_MMIO
select USB_OHCI_LITTLE_ENDIAN
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 259ad282ae5d..c488da5db7c7 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -76,6 +76,7 @@ struct vfio_group {
struct notifier_block nb;
struct list_head vfio_next;
struct list_head container_next;
+ atomic_t opened;
};
struct vfio_device {
@@ -206,6 +207,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
INIT_LIST_HEAD(&group->device_list);
mutex_init(&group->device_lock);
atomic_set(&group->container_users, 0);
+ atomic_set(&group->opened, 0);
group->iommu_group = iommu_group;
group->nb.notifier_call = vfio_iommu_group_notifier;
@@ -1236,12 +1238,22 @@ static long vfio_group_fops_compat_ioctl(struct file *filep,
static int vfio_group_fops_open(struct inode *inode, struct file *filep)
{
struct vfio_group *group;
+ int opened;
group = vfio_group_get_from_minor(iminor(inode));
if (!group)
return -ENODEV;
+ /* Do we need multiple instances of the group open? Seems not. */
+ opened = atomic_cmpxchg(&group->opened, 0, 1);
+ if (opened) {
+ vfio_group_put(group);
+ return -EBUSY;
+ }
+
+ /* Is something still in use from a previous open? */
if (group->container) {
+ atomic_dec(&group->opened);
vfio_group_put(group);
return -EBUSY;
}
@@ -1259,6 +1271,8 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep)
vfio_group_try_dissolve_container(group);
+ atomic_dec(&group->opened);
+
vfio_group_put(group);
return 0;
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 6f3fbc48a6c7..a9807dea3887 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h> /* pci_bus_type */
+#include <linux/rbtree.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -47,19 +48,25 @@ module_param_named(allow_unsafe_interrupts,
MODULE_PARM_DESC(allow_unsafe_interrupts,
"Enable VFIO IOMMU support for on platforms without interrupt remapping support.");
+static bool disable_hugepages;
+module_param_named(disable_hugepages,
+ disable_hugepages, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_hugepages,
+ "Disable VFIO IOMMU support for IOMMU hugepages.");
+
struct vfio_iommu {
struct iommu_domain *domain;
struct mutex lock;
- struct list_head dma_list;
+ struct rb_root dma_list;
struct list_head group_list;
bool cache;
};
struct vfio_dma {
- struct list_head next;
+ struct rb_node node;
dma_addr_t iova; /* Device address */
unsigned long vaddr; /* Process virtual addr */
- long npage; /* Number of pages */
+ size_t size; /* Map size (bytes) */
int prot; /* IOMMU_READ/WRITE */
};
@@ -73,7 +80,48 @@ struct vfio_group {
* into DMA'ble space using the IOMMU
*/
-#define NPAGE_TO_SIZE(npage) ((size_t)(npage) << PAGE_SHIFT)
+static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
+ dma_addr_t start, size_t size)
+{
+ struct rb_node *node = iommu->dma_list.rb_node;
+
+ while (node) {
+ struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
+
+ if (start + size <= dma->iova)
+ node = node->rb_left;
+ else if (start >= dma->iova + dma->size)
+ node = node->rb_right;
+ else
+ return dma;
+ }
+
+ return NULL;
+}
+
+static void vfio_insert_dma(struct vfio_iommu *iommu, struct vfio_dma *new)
+{
+ struct rb_node **link = &iommu->dma_list.rb_node, *parent = NULL;
+ struct vfio_dma *dma;
+
+ while (*link) {
+ parent = *link;
+ dma = rb_entry(parent, struct vfio_dma, node);
+
+ if (new->iova + new->size <= dma->iova)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ rb_link_node(&new->node, parent, link);
+ rb_insert_color(&new->node, &iommu->dma_list);
+}
+
+static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *old)
+{
+ rb_erase(&old->node, &iommu->dma_list);
+}
struct vwork {
struct mm_struct *mm;
@@ -100,8 +148,8 @@ static void vfio_lock_acct(long npage)
struct vwork *vwork;
struct mm_struct *mm;
- if (!current->mm)
- return; /* process exited */
+ if (!current->mm || !npage)
+ return; /* process exited or nothing to do */
if (down_write_trylock(&current->mm->mmap_sem)) {
current->mm->locked_vm += npage;
@@ -173,33 +221,6 @@ static int put_pfn(unsigned long pfn, int prot)
return 0;
}
-/* Unmap DMA region */
-static long __vfio_dma_do_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
- long npage, int prot)
-{
- long i, unlocked = 0;
-
- for (i = 0; i < npage; i++, iova += PAGE_SIZE) {
- unsigned long pfn;
-
- pfn = iommu_iova_to_phys(iommu->domain, iova) >> PAGE_SHIFT;
- if (pfn) {
- iommu_unmap(iommu->domain, iova, PAGE_SIZE);
- unlocked += put_pfn(pfn, prot);
- }
- }
- return unlocked;
-}
-
-static void vfio_dma_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
- long npage, int prot)
-{
- long unlocked;
-
- unlocked = __vfio_dma_do_unmap(iommu, iova, npage, prot);
- vfio_lock_acct(-unlocked);
-}
-
static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
{
struct page *page[1];
@@ -226,198 +247,306 @@ static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
return ret;
}
-/* Map DMA region */
-static int __vfio_dma_map(struct vfio_iommu *iommu, dma_addr_t iova,
- unsigned long vaddr, long npage, int prot)
+/*
+ * Attempt to pin pages. We really don't want to track all the pfns and
+ * the iommu can only map chunks of consecutive pfns anyway, so get the
+ * first page and all consecutive pages with the same locking.
+ */
+static long vfio_pin_pages(unsigned long vaddr, long npage,
+ int prot, unsigned long *pfn_base)
{
- dma_addr_t start = iova;
- long i, locked = 0;
- int ret;
+ unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ bool lock_cap = capable(CAP_IPC_LOCK);
+ long ret, i;
- /* Verify that pages are not already mapped */
- for (i = 0; i < npage; i++, iova += PAGE_SIZE)
- if (iommu_iova_to_phys(iommu->domain, iova))
- return -EBUSY;
+ if (!current->mm)
+ return -ENODEV;
- iova = start;
+ ret = vaddr_get_pfn(vaddr, prot, pfn_base);
+ if (ret)
+ return ret;
- if (iommu->cache)
- prot |= IOMMU_CACHE;
+ if (is_invalid_reserved_pfn(*pfn_base))
+ return 1;
- /*
- * XXX We break mappings into pages and use get_user_pages_fast to
- * pin the pages in memory. It's been suggested that mlock might
- * provide a more efficient mechanism, but nothing prevents the
- * user from munlocking the pages, which could then allow the user
- * access to random host memory. We also have no guarantee from the
- * IOMMU API that the iommu driver can unmap sub-pages of previous
- * mappings. This means we might lose an entire range if a single
- * page within it is unmapped. Single page mappings are inefficient,
- * but provide the most flexibility for now.
- */
- for (i = 0; i < npage; i++, iova += PAGE_SIZE, vaddr += PAGE_SIZE) {
+ if (!lock_cap && current->mm->locked_vm + 1 > limit) {
+ put_pfn(*pfn_base, prot);
+ pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
+ limit << PAGE_SHIFT);
+ return -ENOMEM;
+ }
+
+ if (unlikely(disable_hugepages)) {
+ vfio_lock_acct(1);
+ return 1;
+ }
+
+ /* Lock all the consecutive pages from pfn_base */
+ for (i = 1, vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
unsigned long pfn = 0;
ret = vaddr_get_pfn(vaddr, prot, &pfn);
- if (ret) {
- __vfio_dma_do_unmap(iommu, start, i, prot);
- return ret;
- }
+ if (ret)
+ break;
- /*
- * Only add actual locked pages to accounting
- * XXX We're effectively marking a page locked for every
- * IOVA page even though it's possible the user could be
- * backing multiple IOVAs with the same vaddr. This over-
- * penalizes the user process, but we currently have no
- * easy way to do this properly.
- */
- if (!is_invalid_reserved_pfn(pfn))
- locked++;
+ if (pfn != *pfn_base + i || is_invalid_reserved_pfn(pfn)) {
+ put_pfn(pfn, prot);
+ break;
+ }
- ret = iommu_map(iommu->domain, iova,
- (phys_addr_t)pfn << PAGE_SHIFT,
- PAGE_SIZE, prot);
- if (ret) {
- /* Back out mappings on error */
+ if (!lock_cap && current->mm->locked_vm + i + 1 > limit) {
put_pfn(pfn, prot);
- __vfio_dma_do_unmap(iommu, start, i, prot);
- return ret;
+ pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
+ __func__, limit << PAGE_SHIFT);
+ break;
}
}
- vfio_lock_acct(locked);
- return 0;
+
+ vfio_lock_acct(i);
+
+ return i;
}
-static inline bool ranges_overlap(dma_addr_t start1, size_t size1,
- dma_addr_t start2, size_t size2)
+static long vfio_unpin_pages(unsigned long pfn, long npage,
+ int prot, bool do_accounting)
{
- if (start1 < start2)
- return (start2 - start1 < size1);
- else if (start2 < start1)
- return (start1 - start2 < size2);
- return (size1 > 0 && size2 > 0);
+ unsigned long unlocked = 0;
+ long i;
+
+ for (i = 0; i < npage; i++)
+ unlocked += put_pfn(pfn++, prot);
+
+ if (do_accounting)
+ vfio_lock_acct(-unlocked);
+
+ return unlocked;
}
-static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
- dma_addr_t start, size_t size)
+static int vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
+ dma_addr_t iova, size_t *size)
{
- struct vfio_dma *dma;
+ dma_addr_t start = iova, end = iova + *size;
+ long unlocked = 0;
- list_for_each_entry(dma, &iommu->dma_list, next) {
- if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
- start, size))
- return dma;
+ while (iova < end) {
+ size_t unmapped;
+ phys_addr_t phys;
+
+ /*
+ * We use the IOMMU to track the physical address. This
+ * saves us from having a lot more entries in our mapping
+ * tree. The downside is that we don't track the size
+ * used to do the mapping. We request unmap of a single
+ * page, but expect IOMMUs that support large pages to
+ * unmap a larger chunk.
+ */
+ phys = iommu_iova_to_phys(iommu->domain, iova);
+ if (WARN_ON(!phys)) {
+ iova += PAGE_SIZE;
+ continue;
+ }
+
+ unmapped = iommu_unmap(iommu->domain, iova, PAGE_SIZE);
+ if (!unmapped)
+ break;
+
+ unlocked += vfio_unpin_pages(phys >> PAGE_SHIFT,
+ unmapped >> PAGE_SHIFT,
+ dma->prot, false);
+ iova += unmapped;
}
- return NULL;
+
+ vfio_lock_acct(-unlocked);
+
+ *size = iova - start;
+
+ return 0;
}
-static long vfio_remove_dma_overlap(struct vfio_iommu *iommu, dma_addr_t start,
- size_t size, struct vfio_dma *dma)
+static int vfio_remove_dma_overlap(struct vfio_iommu *iommu, dma_addr_t start,
+ size_t *size, struct vfio_dma *dma)
{
+ size_t offset, overlap, tmp;
struct vfio_dma *split;
- long npage_lo, npage_hi;
-
- /* Existing dma region is completely covered, unmap all */
- if (start <= dma->iova &&
- start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
- vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
- list_del(&dma->next);
- npage_lo = dma->npage;
+ int ret;
+
+ if (!*size)
+ return 0;
+
+ /*
+ * Existing dma region is completely covered, unmap all. This is
+ * the likely case since userspace tends to map and unmap buffers
+ * in one shot rather than multiple mappings within a buffer.
+ */
+ if (likely(start <= dma->iova &&
+ start + *size >= dma->iova + dma->size)) {
+ *size = dma->size;
+ ret = vfio_unmap_unpin(iommu, dma, dma->iova, size);
+ if (ret)
+ return ret;
+
+ /*
+ * Did we remove more than we have? Should never happen
+ * since a vfio_dma is contiguous in iova and vaddr.
+ */
+ WARN_ON(*size != dma->size);
+
+ vfio_remove_dma(iommu, dma);
kfree(dma);
- return npage_lo;
+ return 0;
}
/* Overlap low address of existing range */
if (start <= dma->iova) {
- size_t overlap;
+ overlap = start + *size - dma->iova;
+ ret = vfio_unmap_unpin(iommu, dma, dma->iova, &overlap);
+ if (ret)
+ return ret;
- overlap = start + size - dma->iova;
- npage_lo = overlap >> PAGE_SHIFT;
+ vfio_remove_dma(iommu, dma);
- vfio_dma_unmap(iommu, dma->iova, npage_lo, dma->prot);
- dma->iova += overlap;
- dma->vaddr += overlap;
- dma->npage -= npage_lo;
- return npage_lo;
+ /*
+ * Check, we may have removed to whole vfio_dma. If not
+ * fixup and re-insert.
+ */
+ if (overlap < dma->size) {
+ dma->iova += overlap;
+ dma->vaddr += overlap;
+ dma->size -= overlap;
+ vfio_insert_dma(iommu, dma);
+ } else
+ kfree(dma);
+
+ *size = overlap;
+ return 0;
}
/* Overlap high address of existing range */
- if (start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
- size_t overlap;
+ if (start + *size >= dma->iova + dma->size) {
+ offset = start - dma->iova;
+ overlap = dma->size - offset;
- overlap = dma->iova + NPAGE_TO_SIZE(dma->npage) - start;
- npage_hi = overlap >> PAGE_SHIFT;
+ ret = vfio_unmap_unpin(iommu, dma, start, &overlap);
+ if (ret)
+ return ret;
- vfio_dma_unmap(iommu, start, npage_hi, dma->prot);
- dma->npage -= npage_hi;
- return npage_hi;
+ dma->size -= overlap;
+ *size = overlap;
+ return 0;
}
/* Split existing */
- npage_lo = (start - dma->iova) >> PAGE_SHIFT;
- npage_hi = dma->npage - (size >> PAGE_SHIFT) - npage_lo;
- split = kzalloc(sizeof *split, GFP_KERNEL);
+ /*
+ * Allocate our tracking structure early even though it may not
+ * be used. An Allocation failure later loses track of pages and
+ * is more difficult to unwind.
+ */
+ split = kzalloc(sizeof(*split), GFP_KERNEL);
if (!split)
return -ENOMEM;
- vfio_dma_unmap(iommu, start, size >> PAGE_SHIFT, dma->prot);
+ offset = start - dma->iova;
+
+ ret = vfio_unmap_unpin(iommu, dma, start, size);
+ if (ret || !*size) {
+ kfree(split);
+ return ret;
+ }
+
+ tmp = dma->size;
- dma->npage = npage_lo;
+ /* Resize the lower vfio_dma in place, before the below insert */
+ dma->size = offset;
- split->npage = npage_hi;
- split->iova = start + size;
- split->vaddr = dma->vaddr + NPAGE_TO_SIZE(npage_lo) + size;
- split->prot = dma->prot;
- list_add(&split->next, &iommu->dma_list);
- return size >> PAGE_SHIFT;
+ /* Insert new for remainder, assuming it didn't all get unmapped */
+ if (likely(offset + *size < tmp)) {
+ split->size = tmp - offset - *size;
+ split->iova = dma->iova + offset + *size;
+ split->vaddr = dma->vaddr + offset + *size;
+ split->prot = dma->prot;
+ vfio_insert_dma(iommu, split);
+ } else
+ kfree(split);
+
+ return 0;
}
static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
struct vfio_iommu_type1_dma_unmap *unmap)
{
- long ret = 0, npage = unmap->size >> PAGE_SHIFT;
- struct vfio_dma *dma, *tmp;
uint64_t mask;
+ struct vfio_dma *dma;
+ size_t unmapped = 0, size;
+ int ret = 0;
mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
if (unmap->iova & mask)
return -EINVAL;
- if (unmap->size & mask)
+ if (!unmap->size || unmap->size & mask)
return -EINVAL;
- /* XXX We still break these down into PAGE_SIZE */
WARN_ON(mask & PAGE_MASK);
mutex_lock(&iommu->lock);
- list_for_each_entry_safe(dma, tmp, &iommu->dma_list, next) {
- if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
- unmap->iova, unmap->size)) {
- ret = vfio_remove_dma_overlap(iommu, unmap->iova,
- unmap->size, dma);
- if (ret > 0)
- npage -= ret;
- if (ret < 0 || npage == 0)
- break;
- }
+ while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size))) {
+ size = unmap->size;
+ ret = vfio_remove_dma_overlap(iommu, unmap->iova, &size, dma);
+ if (ret || !size)
+ break;
+ unmapped += size;
}
+
mutex_unlock(&iommu->lock);
- return ret > 0 ? 0 : (int)ret;
+
+ /*
+ * We may unmap more than requested, update the unmap struct so
+ * userspace can know.
+ */
+ unmap->size = unmapped;
+
+ return ret;
+}
+
+/*
+ * Turns out AMD IOMMU has a page table bug where it won't map large pages
+ * to a region that previously mapped smaller pages. This should be fixed
+ * soon, so this is just a temporary workaround to break mappings down into
+ * PAGE_SIZE. Better to map smaller pages than nothing.
+ */
+static int map_try_harder(struct vfio_iommu *iommu, dma_addr_t iova,
+ unsigned long pfn, long npage, int prot)
+{
+ long i;
+ int ret;
+
+ for (i = 0; i < npage; i++, pfn++, iova += PAGE_SIZE) {
+ ret = iommu_map(iommu->domain, iova,
+ (phys_addr_t)pfn << PAGE_SHIFT,
+ PAGE_SIZE, prot);
+ if (ret)
+ break;
+ }
+
+ for (; i < npage && i > 0; i--, iova -= PAGE_SIZE)
+ iommu_unmap(iommu->domain, iova, PAGE_SIZE);
+
+ return ret;
}
static int vfio_dma_do_map(struct vfio_iommu *iommu,
struct vfio_iommu_type1_dma_map *map)
{
- struct vfio_dma *dma, *pdma = NULL;
- dma_addr_t iova = map->iova;
- unsigned long locked, lock_limit, vaddr = map->vaddr;
+ dma_addr_t end, iova;
+ unsigned long vaddr = map->vaddr;
size_t size = map->size;
+ long npage;
int ret = 0, prot = 0;
uint64_t mask;
- long npage;
+
+ end = map->iova + map->size;
mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
@@ -430,104 +559,144 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
if (!prot)
return -EINVAL; /* No READ/WRITE? */
+ if (iommu->cache)
+ prot |= IOMMU_CACHE;
+
if (vaddr & mask)
return -EINVAL;
- if (iova & mask)
+ if (map->iova & mask)
return -EINVAL;
- if (size & mask)
+ if (!map->size || map->size & mask)
return -EINVAL;
- /* XXX We still break these down into PAGE_SIZE */
WARN_ON(mask & PAGE_MASK);
/* Don't allow IOVA wrap */
- if (iova + size && iova + size < iova)
+ if (end && end < map->iova)
return -EINVAL;
/* Don't allow virtual address wrap */
- if (vaddr + size && vaddr + size < vaddr)
- return -EINVAL;
-
- npage = size >> PAGE_SHIFT;
- if (!npage)
+ if (vaddr + map->size && vaddr + map->size < vaddr)
return -EINVAL;
mutex_lock(&iommu->lock);
- if (vfio_find_dma(iommu, iova, size)) {
- ret = -EBUSY;
- goto out_lock;
+ if (vfio_find_dma(iommu, map->iova, map->size)) {
+ mutex_unlock(&iommu->lock);
+ return -EEXIST;
}
- /* account for locked pages */
- locked = current->mm->locked_vm + npage;
- lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
- if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
- pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
- __func__, rlimit(RLIMIT_MEMLOCK));
- ret = -ENOMEM;
- goto out_lock;
- }
+ for (iova = map->iova; iova < end; iova += size, vaddr += size) {
+ struct vfio_dma *dma = NULL;
+ unsigned long pfn;
+ long i;
+
+ /* Pin a contiguous chunk of memory */
+ npage = vfio_pin_pages(vaddr, (end - iova) >> PAGE_SHIFT,
+ prot, &pfn);
+ if (npage <= 0) {
+ WARN_ON(!npage);
+ ret = (int)npage;
+ break;
+ }
- ret = __vfio_dma_map(iommu, iova, vaddr, npage, prot);
- if (ret)
- goto out_lock;
+ /* Verify pages are not already mapped */
+ for (i = 0; i < npage; i++) {
+ if (iommu_iova_to_phys(iommu->domain,
+ iova + (i << PAGE_SHIFT))) {
+ vfio_unpin_pages(pfn, npage, prot, true);
+ ret = -EBUSY;
+ break;
+ }
+ }
- /* Check if we abut a region below - nothing below 0 */
- if (iova) {
- dma = vfio_find_dma(iommu, iova - 1, 1);
- if (dma && dma->prot == prot &&
- dma->vaddr + NPAGE_TO_SIZE(dma->npage) == vaddr) {
+ ret = iommu_map(iommu->domain, iova,
+ (phys_addr_t)pfn << PAGE_SHIFT,
+ npage << PAGE_SHIFT, prot);
+ if (ret) {
+ if (ret != -EBUSY ||
+ map_try_harder(iommu, iova, pfn, npage, prot)) {
+ vfio_unpin_pages(pfn, npage, prot, true);
+ break;
+ }
+ }
- dma->npage += npage;
- iova = dma->iova;
- vaddr = dma->vaddr;
- npage = dma->npage;
- size = NPAGE_TO_SIZE(npage);
+ size = npage << PAGE_SHIFT;
- pdma = dma;
+ /*
+ * Check if we abut a region below - nothing below 0.
+ * This is the most likely case when mapping chunks of
+ * physically contiguous regions within a virtual address
+ * range. Update the abutting entry in place since iova
+ * doesn't change.
+ */
+ if (likely(iova)) {
+ struct vfio_dma *tmp;
+ tmp = vfio_find_dma(iommu, iova - 1, 1);
+ if (tmp && tmp->prot == prot &&
+ tmp->vaddr + tmp->size == vaddr) {
+ tmp->size += size;
+ iova = tmp->iova;
+ size = tmp->size;
+ vaddr = tmp->vaddr;
+ dma = tmp;
+ }
+ }
+
+ /*
+ * Check if we abut a region above - nothing above ~0 + 1.
+ * If we abut above and below, remove and free. If only
+ * abut above, remove, modify, reinsert.
+ */
+ if (likely(iova + size)) {
+ struct vfio_dma *tmp;
+ tmp = vfio_find_dma(iommu, iova + size, 1);
+ if (tmp && tmp->prot == prot &&
+ tmp->vaddr == vaddr + size) {
+ vfio_remove_dma(iommu, tmp);
+ if (dma) {
+ dma->size += tmp->size;
+ kfree(tmp);
+ } else {
+ size += tmp->size;
+ tmp->size = size;
+ tmp->iova = iova;
+ tmp->vaddr = vaddr;
+ vfio_insert_dma(iommu, tmp);
+ dma = tmp;
+ }
+ }
}
- }
- /* Check if we abut a region above - nothing above ~0 + 1 */
- if (iova + size) {
- dma = vfio_find_dma(iommu, iova + size, 1);
- if (dma && dma->prot == prot &&
- dma->vaddr == vaddr + size) {
+ if (!dma) {
+ dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+ if (!dma) {
+ iommu_unmap(iommu->domain, iova, size);
+ vfio_unpin_pages(pfn, npage, prot, true);
+ ret = -ENOMEM;
+ break;
+ }
- dma->npage += npage;
+ dma->size = size;
dma->iova = iova;
dma->vaddr = vaddr;
-
- /*
- * If merged above and below, remove previously
- * merged entry. New entry covers it.
- */
- if (pdma) {
- list_del(&pdma->next);
- kfree(pdma);
- }
- pdma = dma;
+ dma->prot = prot;
+ vfio_insert_dma(iommu, dma);
}
}
- /* Isolated, new region */
- if (!pdma) {
- dma = kzalloc(sizeof *dma, GFP_KERNEL);
- if (!dma) {
- ret = -ENOMEM;
- vfio_dma_unmap(iommu, iova, npage, prot);
- goto out_lock;
+ if (ret) {
+ struct vfio_dma *tmp;
+ iova = map->iova;
+ size = map->size;
+ while ((tmp = vfio_find_dma(iommu, iova, size))) {
+ int r = vfio_remove_dma_overlap(iommu, iova,
+ &size, tmp);
+ if (WARN_ON(r || !size))
+ break;
}
-
- dma->npage = npage;
- dma->iova = iova;
- dma->vaddr = vaddr;
- dma->prot = prot;
- list_add(&dma->next, &iommu->dma_list);
}
-out_lock:
mutex_unlock(&iommu->lock);
return ret;
}
@@ -606,7 +775,7 @@ static void *vfio_iommu_type1_open(unsigned long arg)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&iommu->group_list);
- INIT_LIST_HEAD(&iommu->dma_list);
+ iommu->dma_list = RB_ROOT;
mutex_init(&iommu->lock);
/*
@@ -640,7 +809,7 @@ static void vfio_iommu_type1_release(void *iommu_data)
{
struct vfio_iommu *iommu = iommu_data;
struct vfio_group *group, *group_tmp;
- struct vfio_dma *dma, *dma_tmp;
+ struct rb_node *node;
list_for_each_entry_safe(group, group_tmp, &iommu->group_list, next) {
iommu_detach_group(iommu->domain, group->iommu_group);
@@ -648,10 +817,12 @@ static void vfio_iommu_type1_release(void *iommu_data)
kfree(group);
}
- list_for_each_entry_safe(dma, dma_tmp, &iommu->dma_list, next) {
- vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
- list_del(&dma->next);
- kfree(dma);
+ while ((node = rb_first(&iommu->dma_list))) {
+ struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
+ size_t size = dma->size;
+ vfio_remove_dma_overlap(iommu, dma->iova, &size, dma);
+ if (WARN_ON(!size))
+ break;
}
iommu_domain_free(iommu->domain);
@@ -706,6 +877,7 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
} else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
struct vfio_iommu_type1_dma_unmap unmap;
+ long ret;
minsz = offsetofend(struct vfio_iommu_type1_dma_unmap, size);
@@ -715,7 +887,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
if (unmap.argsz < minsz || unmap.flags)
return -EINVAL;
- return vfio_dma_do_unmap(iommu, &unmap);
+ ret = vfio_dma_do_unmap(iommu, &unmap);
+ if (ret)
+ return ret;
+
+ return copy_to_user((void __user *)arg, &unmap, minsz);
}
return -ENOTTY;
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
index 8b9226da3f54..017a1e8a8f6f 100644
--- a/drivers/vhost/Kconfig
+++ b/drivers/vhost/Kconfig
@@ -1,6 +1,7 @@
config VHOST_NET
tristate "Host kernel accelerator for virtio net"
depends on NET && EVENTFD && (TUN || !TUN) && (MACVTAP || !MACVTAP)
+ select VHOST
select VHOST_RING
---help---
This kernel module can be loaded in host kernel to accelerate
@@ -13,6 +14,7 @@ config VHOST_NET
config VHOST_SCSI
tristate "VHOST_SCSI TCM fabric driver"
depends on TARGET_CORE && EVENTFD && m
+ select VHOST
select VHOST_RING
default n
---help---
@@ -24,3 +26,9 @@ config VHOST_RING
---help---
This option is selected by any driver which needs to access
the host side of a virtio ring.
+
+config VHOST
+ tristate
+ ---help---
+ This option is selected by any driver which needs to access
+ the core of vhost.
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
index 654e9afb11f5..e0441c34db1c 100644
--- a/drivers/vhost/Makefile
+++ b/drivers/vhost/Makefile
@@ -1,7 +1,8 @@
obj-$(CONFIG_VHOST_NET) += vhost_net.o
-vhost_net-y := vhost.o net.o
+vhost_net-y := net.o
obj-$(CONFIG_VHOST_SCSI) += vhost_scsi.o
vhost_scsi-y := scsi.o
obj-$(CONFIG_VHOST_RING) += vringh.o
+obj-$(CONFIG_VHOST) += vhost.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 8ca5ac71b845..027be91db139 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -168,7 +168,7 @@ static void vhost_net_clear_ubuf_info(struct vhost_net *n)
}
}
-int vhost_net_set_ubuf_info(struct vhost_net *n)
+static int vhost_net_set_ubuf_info(struct vhost_net *n)
{
bool zcopy;
int i;
@@ -189,7 +189,7 @@ err:
return -ENOMEM;
}
-void vhost_net_vq_reset(struct vhost_net *n)
+static void vhost_net_vq_reset(struct vhost_net *n)
{
int i;
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 701420297225..06adf31a9248 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -49,7 +49,6 @@
#include <linux/llist.h>
#include <linux/bitmap.h>
-#include "vhost.c"
#include "vhost.h"
#define TCM_VHOST_VERSION "v0.1"
@@ -116,7 +115,6 @@ struct tcm_vhost_nacl {
struct se_node_acl se_node_acl;
};
-struct vhost_scsi;
struct tcm_vhost_tpg {
/* Vhost port target portal group tag for TCM */
u16 tport_tpgt;
@@ -218,7 +216,7 @@ static int iov_num_pages(struct iovec *iov)
((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT;
}
-void tcm_vhost_done_inflight(struct kref *kref)
+static void tcm_vhost_done_inflight(struct kref *kref)
{
struct vhost_scsi_inflight *inflight;
@@ -329,11 +327,12 @@ static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
return 1;
}
-static u32 tcm_vhost_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)
+static u32
+tcm_vhost_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)
{
struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
@@ -359,10 +358,11 @@ static u32 tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
format_code, buf);
}
-static u32 tcm_vhost_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)
+static u32
+tcm_vhost_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)
{
struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
@@ -388,10 +388,11 @@ static u32 tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
format_code);
}
-static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
- const char *buf,
- u32 *out_tid_len,
- char **port_nexus_ptr)
+static char *
+tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
{
struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
@@ -417,8 +418,8 @@ static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
port_nexus_ptr);
}
-static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
- struct se_portal_group *se_tpg)
+static struct se_node_acl *
+tcm_vhost_alloc_fabric_acl(struct se_portal_group *se_tpg)
{
struct tcm_vhost_nacl *nacl;
@@ -431,8 +432,9 @@ static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
return &nacl->se_node_acl;
}
-static void tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
- struct se_node_acl *se_nacl)
+static void
+tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
{
struct tcm_vhost_nacl *nacl = container_of(se_nacl,
struct tcm_vhost_nacl, se_node_acl);
@@ -446,7 +448,19 @@ static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
{
- return;
+ struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+ struct tcm_vhost_cmd, tvc_se_cmd);
+
+ if (tv_cmd->tvc_sgl_count) {
+ u32 i;
+ for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+ put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+
+ kfree(tv_cmd->tvc_sgl);
+ }
+
+ tcm_vhost_put_inflight(tv_cmd->inflight);
+ kfree(tv_cmd);
}
static int tcm_vhost_shutdown_session(struct se_session *se_sess)
@@ -491,34 +505,34 @@ static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
return 0;
}
-static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd)
+static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *cmd)
{
- struct vhost_scsi *vs = tv_cmd->tvc_vhost;
+ struct vhost_scsi *vs = cmd->tvc_vhost;
- llist_add(&tv_cmd->tvc_completion_list, &vs->vs_completion_list);
+ llist_add(&cmd->tvc_completion_list, &vs->vs_completion_list);
vhost_work_queue(&vs->dev, &vs->vs_completion_work);
}
static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+ struct tcm_vhost_cmd *cmd = container_of(se_cmd,
struct tcm_vhost_cmd, tvc_se_cmd);
- vhost_scsi_complete_cmd(tv_cmd);
+ vhost_scsi_complete_cmd(cmd);
return 0;
}
static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+ struct tcm_vhost_cmd *cmd = container_of(se_cmd,
struct tcm_vhost_cmd, tvc_se_cmd);
- vhost_scsi_complete_cmd(tv_cmd);
+ vhost_scsi_complete_cmd(cmd);
return 0;
}
-static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
{
- return 0;
+ return;
}
static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
@@ -527,8 +541,9 @@ static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
kfree(evt);
}
-static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,
- u32 event, u32 reason)
+static struct tcm_vhost_evt *
+tcm_vhost_allocate_evt(struct vhost_scsi *vs,
+ u32 event, u32 reason)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
struct tcm_vhost_evt *evt;
@@ -552,28 +567,22 @@ static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,
return evt;
}
-static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
+static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *cmd)
{
- struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+ struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
/* TODO locking against target/backend threads? */
- transport_generic_free_cmd(se_cmd, 1);
-
- if (tv_cmd->tvc_sgl_count) {
- u32 i;
- for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
- put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+ transport_generic_free_cmd(se_cmd, 0);
- kfree(tv_cmd->tvc_sgl);
- }
-
- tcm_vhost_put_inflight(tv_cmd->inflight);
+}
- kfree(tv_cmd);
+static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
+{
+ return target_put_sess_cmd(se_cmd->se_sess, se_cmd);
}
-static void tcm_vhost_do_evt_work(struct vhost_scsi *vs,
- struct tcm_vhost_evt *evt)
+static void
+tcm_vhost_do_evt_work(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
struct virtio_scsi_event *event = &evt->event;
@@ -652,7 +661,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
vs_completion_work);
DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
struct virtio_scsi_cmd_resp v_rsp;
- struct tcm_vhost_cmd *tv_cmd;
+ struct tcm_vhost_cmd *cmd;
struct llist_node *llnode;
struct se_cmd *se_cmd;
int ret, vq;
@@ -660,32 +669,32 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
llnode = llist_del_all(&vs->vs_completion_list);
while (llnode) {
- tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd,
+ cmd = llist_entry(llnode, struct tcm_vhost_cmd,
tvc_completion_list);
llnode = llist_next(llnode);
- se_cmd = &tv_cmd->tvc_se_cmd;
+ se_cmd = &cmd->tvc_se_cmd;
pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
- tv_cmd, se_cmd->residual_count, se_cmd->scsi_status);
+ cmd, se_cmd->residual_count, se_cmd->scsi_status);
memset(&v_rsp, 0, sizeof(v_rsp));
v_rsp.resid = se_cmd->residual_count;
/* TODO is status_qualifier field needed? */
v_rsp.status = se_cmd->scsi_status;
v_rsp.sense_len = se_cmd->scsi_sense_length;
- memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf,
+ memcpy(v_rsp.sense, cmd->tvc_sense_buf,
v_rsp.sense_len);
- ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
+ ret = copy_to_user(cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
if (likely(ret == 0)) {
struct vhost_scsi_virtqueue *q;
- vhost_add_used(tv_cmd->tvc_vq, tv_cmd->tvc_vq_desc, 0);
- q = container_of(tv_cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
+ vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
+ q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
vq = q - vs->vqs;
__set_bit(vq, signal);
} else
pr_err("Faulted on virtio_scsi_cmd_resp\n");
- vhost_scsi_free_cmd(tv_cmd);
+ vhost_scsi_free_cmd(cmd);
}
vq = -1;
@@ -694,35 +703,35 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
vhost_signal(&vs->dev, &vs->vqs[vq].vq);
}
-static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
- struct vhost_virtqueue *vq,
- struct tcm_vhost_tpg *tv_tpg,
- struct virtio_scsi_cmd_req *v_req,
- u32 exp_data_len,
- int data_direction)
+static struct tcm_vhost_cmd *
+vhost_scsi_allocate_cmd(struct vhost_virtqueue *vq,
+ struct tcm_vhost_tpg *tpg,
+ struct virtio_scsi_cmd_req *v_req,
+ u32 exp_data_len,
+ int data_direction)
{
- struct tcm_vhost_cmd *tv_cmd;
+ struct tcm_vhost_cmd *cmd;
struct tcm_vhost_nexus *tv_nexus;
- tv_nexus = tv_tpg->tpg_nexus;
+ tv_nexus = tpg->tpg_nexus;
if (!tv_nexus) {
pr_err("Unable to locate active struct tcm_vhost_nexus\n");
return ERR_PTR(-EIO);
}
- tv_cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
- if (!tv_cmd) {
+ cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
+ if (!cmd) {
pr_err("Unable to allocate struct tcm_vhost_cmd\n");
return ERR_PTR(-ENOMEM);
}
- tv_cmd->tvc_tag = v_req->tag;
- tv_cmd->tvc_task_attr = v_req->task_attr;
- tv_cmd->tvc_exp_data_len = exp_data_len;
- tv_cmd->tvc_data_direction = data_direction;
- tv_cmd->tvc_nexus = tv_nexus;
- tv_cmd->inflight = tcm_vhost_get_inflight(vq);
+ cmd->tvc_tag = v_req->tag;
+ cmd->tvc_task_attr = v_req->task_attr;
+ cmd->tvc_exp_data_len = exp_data_len;
+ cmd->tvc_data_direction = data_direction;
+ cmd->tvc_nexus = tv_nexus;
+ cmd->inflight = tcm_vhost_get_inflight(vq);
- return tv_cmd;
+ return cmd;
}
/*
@@ -730,8 +739,11 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
*
* Returns the number of scatterlist entries used or -errno on error.
*/
-static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
- unsigned int sgl_count, struct iovec *iov, int write)
+static int
+vhost_scsi_map_to_sgl(struct scatterlist *sgl,
+ unsigned int sgl_count,
+ struct iovec *iov,
+ int write)
{
unsigned int npages = 0, pages_nr, offset, nbytes;
struct scatterlist *sg = sgl;
@@ -775,8 +787,11 @@ out:
return ret;
}
-static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
- struct iovec *iov, unsigned int niov, int write)
+static int
+vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
+ struct iovec *iov,
+ unsigned int niov,
+ int write)
{
int ret;
unsigned int i;
@@ -792,25 +807,25 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
/* TODO overflow checking */
- sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
+ sg = kmalloc(sizeof(cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
if (!sg)
return -ENOMEM;
pr_debug("%s sg %p sgl_count %u is_err %d\n", __func__,
sg, sgl_count, !sg);
sg_init_table(sg, sgl_count);
- tv_cmd->tvc_sgl = sg;
- tv_cmd->tvc_sgl_count = sgl_count;
+ cmd->tvc_sgl = sg;
+ cmd->tvc_sgl_count = sgl_count;
pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
for (i = 0; i < niov; i++) {
ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write);
if (ret < 0) {
- for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
- put_page(sg_page(&tv_cmd->tvc_sgl[i]));
- kfree(tv_cmd->tvc_sgl);
- tv_cmd->tvc_sgl = NULL;
- tv_cmd->tvc_sgl_count = 0;
+ for (i = 0; i < cmd->tvc_sgl_count; i++)
+ put_page(sg_page(&cmd->tvc_sgl[i]));
+ kfree(cmd->tvc_sgl);
+ cmd->tvc_sgl = NULL;
+ cmd->tvc_sgl_count = 0;
return ret;
}
@@ -822,15 +837,15 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
static void tcm_vhost_submission_work(struct work_struct *work)
{
- struct tcm_vhost_cmd *tv_cmd =
+ struct tcm_vhost_cmd *cmd =
container_of(work, struct tcm_vhost_cmd, work);
struct tcm_vhost_nexus *tv_nexus;
- struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+ struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
int rc, sg_no_bidi = 0;
- if (tv_cmd->tvc_sgl_count) {
- sg_ptr = tv_cmd->tvc_sgl;
+ if (cmd->tvc_sgl_count) {
+ sg_ptr = cmd->tvc_sgl;
/* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
#if 0
if (se_cmd->se_cmd_flags & SCF_BIDI) {
@@ -841,13 +856,13 @@ static void tcm_vhost_submission_work(struct work_struct *work)
} else {
sg_ptr = NULL;
}
- tv_nexus = tv_cmd->tvc_nexus;
+ tv_nexus = cmd->tvc_nexus;
rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess,
- tv_cmd->tvc_cdb, &tv_cmd->tvc_sense_buf[0],
- tv_cmd->tvc_lun, tv_cmd->tvc_exp_data_len,
- tv_cmd->tvc_task_attr, tv_cmd->tvc_data_direction,
- 0, sg_ptr, tv_cmd->tvc_sgl_count,
+ cmd->tvc_cdb, &cmd->tvc_sense_buf[0],
+ cmd->tvc_lun, cmd->tvc_exp_data_len,
+ cmd->tvc_task_attr, cmd->tvc_data_direction,
+ TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
sg_bidi_ptr, sg_no_bidi);
if (rc < 0) {
transport_send_check_condition_and_sense(se_cmd,
@@ -856,8 +871,10 @@ static void tcm_vhost_submission_work(struct work_struct *work)
}
}
-static void vhost_scsi_send_bad_target(struct vhost_scsi *vs,
- struct vhost_virtqueue *vq, int head, unsigned out)
+static void
+vhost_scsi_send_bad_target(struct vhost_scsi *vs,
+ struct vhost_virtqueue *vq,
+ int head, unsigned out)
{
struct virtio_scsi_cmd_resp __user *resp;
struct virtio_scsi_cmd_resp rsp;
@@ -873,13 +890,13 @@ static void vhost_scsi_send_bad_target(struct vhost_scsi *vs,
pr_err("Faulted on virtio_scsi_cmd_resp\n");
}
-static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
- struct vhost_virtqueue *vq)
+static void
+vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{
struct tcm_vhost_tpg **vs_tpg;
struct virtio_scsi_cmd_req v_req;
- struct tcm_vhost_tpg *tv_tpg;
- struct tcm_vhost_cmd *tv_cmd;
+ struct tcm_vhost_tpg *tpg;
+ struct tcm_vhost_cmd *cmd;
u32 exp_data_len, data_first, data_num, data_direction;
unsigned out, in, i;
int head, ret;
@@ -964,10 +981,10 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
/* Extract the tpgt */
target = v_req.lun[1];
- tv_tpg = ACCESS_ONCE(vs_tpg[target]);
+ tpg = ACCESS_ONCE(vs_tpg[target]);
/* Target does not exist, fail the request */
- if (unlikely(!tv_tpg)) {
+ if (unlikely(!tpg)) {
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
@@ -976,46 +993,46 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
for (i = 0; i < data_num; i++)
exp_data_len += vq->iov[data_first + i].iov_len;
- tv_cmd = vhost_scsi_allocate_cmd(vq, tv_tpg, &v_req,
+ cmd = vhost_scsi_allocate_cmd(vq, tpg, &v_req,
exp_data_len, data_direction);
- if (IS_ERR(tv_cmd)) {
+ if (IS_ERR(cmd)) {
vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
- PTR_ERR(tv_cmd));
+ PTR_ERR(cmd));
goto err_cmd;
}
pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
- ": %d\n", tv_cmd, exp_data_len, data_direction);
+ ": %d\n", cmd, exp_data_len, data_direction);
- tv_cmd->tvc_vhost = vs;
- tv_cmd->tvc_vq = vq;
- tv_cmd->tvc_resp = vq->iov[out].iov_base;
+ cmd->tvc_vhost = vs;
+ cmd->tvc_vq = vq;
+ cmd->tvc_resp = vq->iov[out].iov_base;
/*
- * Copy in the recieved CDB descriptor into tv_cmd->tvc_cdb
+ * Copy in the recieved CDB descriptor into cmd->tvc_cdb
* that will be used by tcm_vhost_new_cmd_map() and down into
* target_setup_cmd_from_cdb()
*/
- memcpy(tv_cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
+ memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
/*
* Check that the recieved CDB size does not exceeded our
* hardcoded max for tcm_vhost
*/
/* TODO what if cdb was too small for varlen cdb header? */
- if (unlikely(scsi_command_size(tv_cmd->tvc_cdb) >
+ if (unlikely(scsi_command_size(cmd->tvc_cdb) >
TCM_VHOST_MAX_CDB_SIZE)) {
vq_err(vq, "Received SCSI CDB with command_size: %d that"
" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
- scsi_command_size(tv_cmd->tvc_cdb),
+ scsi_command_size(cmd->tvc_cdb),
TCM_VHOST_MAX_CDB_SIZE);
goto err_free;
}
- tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
+ cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
- tv_cmd->tvc_cdb[0], tv_cmd->tvc_lun);
+ cmd->tvc_cdb[0], cmd->tvc_lun);
if (data_direction != DMA_NONE) {
- ret = vhost_scsi_map_iov_to_sgl(tv_cmd,
+ ret = vhost_scsi_map_iov_to_sgl(cmd,
&vq->iov[data_first], data_num,
data_direction == DMA_TO_DEVICE);
if (unlikely(ret)) {
@@ -1029,22 +1046,22 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
* complete the virtio-scsi request in TCM callback context via
* tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
*/
- tv_cmd->tvc_vq_desc = head;
+ cmd->tvc_vq_desc = head;
/*
* Dispatch tv_cmd descriptor for cmwq execution in process
* context provided by tcm_vhost_workqueue. This also ensures
* tv_cmd is executed on the same kworker CPU as this vhost
* thread to gain positive L2 cache locality effects..
*/
- INIT_WORK(&tv_cmd->work, tcm_vhost_submission_work);
- queue_work(tcm_vhost_workqueue, &tv_cmd->work);
+ INIT_WORK(&cmd->work, tcm_vhost_submission_work);
+ queue_work(tcm_vhost_workqueue, &cmd->work);
}
mutex_unlock(&vq->mutex);
return;
err_free:
- vhost_scsi_free_cmd(tv_cmd);
+ vhost_scsi_free_cmd(cmd);
err_cmd:
vhost_scsi_send_bad_target(vs, vq, head, out);
mutex_unlock(&vq->mutex);
@@ -1055,8 +1072,12 @@ static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
pr_debug("%s: The handling func for control queue.\n", __func__);
}
-static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg,
- struct se_lun *lun, u32 event, u32 reason)
+static void
+tcm_vhost_send_evt(struct vhost_scsi *vs,
+ struct tcm_vhost_tpg *tpg,
+ struct se_lun *lun,
+ u32 event,
+ u32 reason)
{
struct tcm_vhost_evt *evt;
@@ -1146,12 +1167,12 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
* The lock nesting rule is:
* tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
*/
-static int vhost_scsi_set_endpoint(
- struct vhost_scsi *vs,
- struct vhost_scsi_target *t)
+static int
+vhost_scsi_set_endpoint(struct vhost_scsi *vs,
+ struct vhost_scsi_target *t)
{
struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tv_tpg;
+ struct tcm_vhost_tpg *tpg;
struct tcm_vhost_tpg **vs_tpg;
struct vhost_virtqueue *vq;
int index, ret, i, len;
@@ -1178,32 +1199,32 @@ static int vhost_scsi_set_endpoint(
if (vs->vs_tpg)
memcpy(vs_tpg, vs->vs_tpg, len);
- list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- if (!tv_tpg->tpg_nexus) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ list_for_each_entry(tpg, &tcm_vhost_list, tv_tpg_list) {
+ mutex_lock(&tpg->tv_tpg_mutex);
+ if (!tpg->tpg_nexus) {
+ mutex_unlock(&tpg->tv_tpg_mutex);
continue;
}
- if (tv_tpg->tv_tpg_vhost_count != 0) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ if (tpg->tv_tpg_vhost_count != 0) {
+ mutex_unlock(&tpg->tv_tpg_mutex);
continue;
}
- tv_tport = tv_tpg->tport;
+ tv_tport = tpg->tport;
if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
- if (vs->vs_tpg && vs->vs_tpg[tv_tpg->tport_tpgt]) {
+ if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) {
kfree(vs_tpg);
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
ret = -EEXIST;
goto out;
}
- tv_tpg->tv_tpg_vhost_count++;
- tv_tpg->vhost_scsi = vs;
- vs_tpg[tv_tpg->tport_tpgt] = tv_tpg;
+ tpg->tv_tpg_vhost_count++;
+ tpg->vhost_scsi = vs;
+ vs_tpg[tpg->tport_tpgt] = tpg;
smp_mb__after_atomic_inc();
match = true;
}
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
}
if (match) {
@@ -1236,12 +1257,12 @@ out:
return ret;
}
-static int vhost_scsi_clear_endpoint(
- struct vhost_scsi *vs,
- struct vhost_scsi_target *t)
+static int
+vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
+ struct vhost_scsi_target *t)
{
struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tv_tpg;
+ struct tcm_vhost_tpg *tpg;
struct vhost_virtqueue *vq;
bool match = false;
int index, ret, i;
@@ -1264,30 +1285,30 @@ static int vhost_scsi_clear_endpoint(
for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
target = i;
- tv_tpg = vs->vs_tpg[target];
- if (!tv_tpg)
+ tpg = vs->vs_tpg[target];
+ if (!tpg)
continue;
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- tv_tport = tv_tpg->tport;
+ mutex_lock(&tpg->tv_tpg_mutex);
+ tv_tport = tpg->tport;
if (!tv_tport) {
ret = -ENODEV;
goto err_tpg;
}
if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
- pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu"
+ pr_warn("tv_tport->tport_name: %s, tpg->tport_tpgt: %hu"
" does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n",
- tv_tport->tport_name, tv_tpg->tport_tpgt,
+ tv_tport->tport_name, tpg->tport_tpgt,
t->vhost_wwpn, t->vhost_tpgt);
ret = -EINVAL;
goto err_tpg;
}
- tv_tpg->tv_tpg_vhost_count--;
- tv_tpg->vhost_scsi = NULL;
+ tpg->tv_tpg_vhost_count--;
+ tpg->vhost_scsi = NULL;
vs->vs_tpg[target] = NULL;
match = true;
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
}
if (match) {
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
@@ -1311,7 +1332,7 @@ static int vhost_scsi_clear_endpoint(
return 0;
err_tpg:
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
err_dev:
mutex_unlock(&vs->dev.mutex);
mutex_unlock(&tcm_vhost_mutex);
@@ -1338,68 +1359,70 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
static int vhost_scsi_open(struct inode *inode, struct file *f)
{
- struct vhost_scsi *s;
+ struct vhost_scsi *vs;
struct vhost_virtqueue **vqs;
int r, i;
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s)
+ vs = kzalloc(sizeof(*vs), GFP_KERNEL);
+ if (!vs)
return -ENOMEM;
vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL);
if (!vqs) {
- kfree(s);
+ kfree(vs);
return -ENOMEM;
}
- vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);
- vhost_work_init(&s->vs_event_work, tcm_vhost_evt_work);
+ vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
+ vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
- s->vs_events_nr = 0;
- s->vs_events_missed = false;
+ vs->vs_events_nr = 0;
+ vs->vs_events_missed = false;
- vqs[VHOST_SCSI_VQ_CTL] = &s->vqs[VHOST_SCSI_VQ_CTL].vq;
- vqs[VHOST_SCSI_VQ_EVT] = &s->vqs[VHOST_SCSI_VQ_EVT].vq;
- s->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
- s->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
+ vqs[VHOST_SCSI_VQ_CTL] = &vs->vqs[VHOST_SCSI_VQ_CTL].vq;
+ vqs[VHOST_SCSI_VQ_EVT] = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
+ vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
+ vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
- vqs[i] = &s->vqs[i].vq;
- s->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
+ vqs[i] = &vs->vqs[i].vq;
+ vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
}
- r = vhost_dev_init(&s->dev, vqs, VHOST_SCSI_MAX_VQ);
+ r = vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
- tcm_vhost_init_inflight(s, NULL);
+ tcm_vhost_init_inflight(vs, NULL);
if (r < 0) {
kfree(vqs);
- kfree(s);
+ kfree(vs);
return r;
}
- f->private_data = s;
+ f->private_data = vs;
return 0;
}
static int vhost_scsi_release(struct inode *inode, struct file *f)
{
- struct vhost_scsi *s = f->private_data;
+ struct vhost_scsi *vs = f->private_data;
struct vhost_scsi_target t;
- mutex_lock(&s->dev.mutex);
- memcpy(t.vhost_wwpn, s->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
- mutex_unlock(&s->dev.mutex);
- vhost_scsi_clear_endpoint(s, &t);
- vhost_dev_stop(&s->dev);
- vhost_dev_cleanup(&s->dev, false);
+ mutex_lock(&vs->dev.mutex);
+ memcpy(t.vhost_wwpn, vs->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
+ mutex_unlock(&vs->dev.mutex);
+ vhost_scsi_clear_endpoint(vs, &t);
+ vhost_dev_stop(&vs->dev);
+ vhost_dev_cleanup(&vs->dev, false);
/* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
- vhost_scsi_flush(s);
- kfree(s->dev.vqs);
- kfree(s);
+ vhost_scsi_flush(vs);
+ kfree(vs->dev.vqs);
+ kfree(vs);
return 0;
}
-static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
- unsigned long arg)
+static long
+vhost_scsi_ioctl(struct file *f,
+ unsigned int ioctl,
+ unsigned long arg)
{
struct vhost_scsi *vs = f->private_data;
struct vhost_scsi_target backend;
@@ -1515,8 +1538,9 @@ static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
return "Unknown";
}
-static void tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
- struct se_lun *lun, bool plug)
+static void
+tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
+ struct se_lun *lun, bool plug)
{
struct vhost_scsi *vs = tpg->vhost_scsi;
@@ -1556,18 +1580,18 @@ static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
}
static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
- struct se_lun *lun)
+ struct se_lun *lun)
{
- struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+ struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
mutex_lock(&tcm_vhost_mutex);
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- tv_tpg->tv_tpg_port_count++;
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_lock(&tpg->tv_tpg_mutex);
+ tpg->tv_tpg_port_count++;
+ mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotplug(tv_tpg, lun);
+ tcm_vhost_hotplug(tpg, lun);
mutex_unlock(&tcm_vhost_mutex);
@@ -1575,26 +1599,26 @@ static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
}
static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
- struct se_lun *lun)
+ struct se_lun *lun)
{
- struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+ struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
mutex_lock(&tcm_vhost_mutex);
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- tv_tpg->tv_tpg_port_count--;
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_lock(&tpg->tv_tpg_mutex);
+ tpg->tv_tpg_port_count--;
+ mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotunplug(tv_tpg, lun);
+ tcm_vhost_hotunplug(tpg, lun);
mutex_unlock(&tcm_vhost_mutex);
}
-static struct se_node_acl *tcm_vhost_make_nodeacl(
- struct se_portal_group *se_tpg,
- struct config_group *group,
- const char *name)
+static struct se_node_acl *
+tcm_vhost_make_nodeacl(struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
{
struct se_node_acl *se_nacl, *se_nacl_new;
struct tcm_vhost_nacl *nacl;
@@ -1635,23 +1659,23 @@ static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
kfree(nacl);
}
-static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
- const char *name)
+static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
+ const char *name)
{
struct se_portal_group *se_tpg;
struct tcm_vhost_nexus *tv_nexus;
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- if (tv_tpg->tpg_nexus) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
- pr_debug("tv_tpg->tpg_nexus already exists\n");
+ mutex_lock(&tpg->tv_tpg_mutex);
+ if (tpg->tpg_nexus) {
+ mutex_unlock(&tpg->tv_tpg_mutex);
+ pr_debug("tpg->tpg_nexus already exists\n");
return -EEXIST;
}
- se_tpg = &tv_tpg->se_tpg;
+ se_tpg = &tpg->se_tpg;
tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
if (!tv_nexus) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate struct tcm_vhost_nexus\n");
return -ENOMEM;
}
@@ -1660,7 +1684,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
*/
tv_nexus->tvn_se_sess = transport_init_session();
if (IS_ERR(tv_nexus->tvn_se_sess)) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
kfree(tv_nexus);
return -ENOMEM;
}
@@ -1672,7 +1696,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
se_tpg, (unsigned char *)name);
if (!tv_nexus->tvn_se_sess->se_node_acl) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
pr_debug("core_tpg_check_initiator_node_acl() failed"
" for %s\n", name);
transport_free_session(tv_nexus->tvn_se_sess);
@@ -1685,9 +1709,9 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
*/
__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
tv_nexus->tvn_se_sess, tv_nexus);
- tv_tpg->tpg_nexus = tv_nexus;
+ tpg->tpg_nexus = tv_nexus;
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
return 0;
}
@@ -1740,40 +1764,40 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
}
static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
- char *page)
+ char *page)
{
- struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+ struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
struct tcm_vhost_nexus *tv_nexus;
ssize_t ret;
- mutex_lock(&tv_tpg->tv_tpg_mutex);
- tv_nexus = tv_tpg->tpg_nexus;
+ mutex_lock(&tpg->tv_tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
if (!tv_nexus) {
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
return -ENODEV;
}
ret = snprintf(page, PAGE_SIZE, "%s\n",
tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
- mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ mutex_unlock(&tpg->tv_tpg_mutex);
return ret;
}
static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+ const char *page,
+ size_t count)
{
- struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+ struct tcm_vhost_tpg *tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport_wwn = tv_tpg->tport;
+ struct tcm_vhost_tport *tport_wwn = tpg->tport;
unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
int ret;
/*
* Shutdown the active I_T nexus if 'NULL' is passed..
*/
if (!strncmp(page, "NULL", 4)) {
- ret = tcm_vhost_drop_nexus(tv_tpg);
+ ret = tcm_vhost_drop_nexus(tpg);
return (!ret) ? count : ret;
}
/*
@@ -1831,7 +1855,7 @@ check_newline:
if (i_port[strlen(i_port)-1] == '\n')
i_port[strlen(i_port)-1] = '\0';
- ret = tcm_vhost_make_nexus(tv_tpg, port_ptr);
+ ret = tcm_vhost_make_nexus(tpg, port_ptr);
if (ret < 0)
return ret;
@@ -1845,9 +1869,10 @@ static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
NULL,
};
-static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn,
- struct config_group *group,
- const char *name)
+static struct se_portal_group *
+tcm_vhost_make_tpg(struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
{
struct tcm_vhost_tport *tport = container_of(wwn,
struct tcm_vhost_tport, tport_wwn);
@@ -1903,9 +1928,10 @@ static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
kfree(tpg);
}
-static struct se_wwn *tcm_vhost_make_tport(struct target_fabric_configfs *tf,
- struct config_group *group,
- const char *name)
+static struct se_wwn *
+tcm_vhost_make_tport(struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
{
struct tcm_vhost_tport *tport;
char *ptr;
@@ -1975,9 +2001,9 @@ static void tcm_vhost_drop_tport(struct se_wwn *wwn)
kfree(tport);
}
-static ssize_t tcm_vhost_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t
+tcm_vhost_wwn_show_attr_version(struct target_fabric_configfs *tf,
+ char *page)
{
return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
"on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
@@ -2008,6 +2034,7 @@ static struct target_core_fabric_ops tcm_vhost_ops = {
.tpg_release_fabric_acl = tcm_vhost_release_fabric_acl,
.tpg_get_inst_index = tcm_vhost_tpg_get_inst_index,
.release_cmd = tcm_vhost_release_cmd,
+ .check_stop_free = vhost_scsi_check_stop_free,
.shutdown_session = tcm_vhost_shutdown_session,
.close_session = tcm_vhost_close_session,
.sess_get_index = tcm_vhost_sess_get_index,
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
index 1ee45bc85f67..a73ea217f24d 100644
--- a/drivers/vhost/test.c
+++ b/drivers/vhost/test.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include "test.h"
-#include "vhost.c"
+#include "vhost.h"
/* Max number of bytes transferred before requeueing the job.
* Using this limit prevents one virtqueue from starving others. */
@@ -38,17 +38,19 @@ struct vhost_test {
* read-size critical section for our kind of RCU. */
static void handle_vq(struct vhost_test *n)
{
- struct vhost_virtqueue *vq = &n->dev.vqs[VHOST_TEST_VQ];
+ struct vhost_virtqueue *vq = &n->vqs[VHOST_TEST_VQ];
unsigned out, in;
int head;
size_t len, total_len = 0;
void *private;
- private = rcu_dereference_check(vq->private_data, 1);
- if (!private)
+ mutex_lock(&vq->mutex);
+ private = vq->private_data;
+ if (!private) {
+ mutex_unlock(&vq->mutex);
return;
+ }
- mutex_lock(&vq->mutex);
vhost_disable_notify(&n->dev, vq);
for (;;) {
@@ -102,15 +104,23 @@ static int vhost_test_open(struct inode *inode, struct file *f)
{
struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL);
struct vhost_dev *dev;
+ struct vhost_virtqueue **vqs;
int r;
if (!n)
return -ENOMEM;
+ vqs = kmalloc(VHOST_TEST_VQ_MAX * sizeof(*vqs), GFP_KERNEL);
+ if (!vqs) {
+ kfree(n);
+ return -ENOMEM;
+ }
dev = &n->dev;
+ vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ];
n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
- r = vhost_dev_init(dev, n->vqs, VHOST_TEST_VQ_MAX);
+ r = vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX);
if (r < 0) {
+ kfree(vqs);
kfree(n);
return r;
}
@@ -126,9 +136,8 @@ static void *vhost_test_stop_vq(struct vhost_test *n,
void *private;
mutex_lock(&vq->mutex);
- private = rcu_dereference_protected(vq->private_data,
- lockdep_is_held(&vq->mutex));
- rcu_assign_pointer(vq->private_data, NULL);
+ private = vq->private_data;
+ vq->private_data = NULL;
mutex_unlock(&vq->mutex);
return private;
}
@@ -140,7 +149,7 @@ static void vhost_test_stop(struct vhost_test *n, void **privatep)
static void vhost_test_flush_vq(struct vhost_test *n, int index)
{
- vhost_poll_flush(&n->dev.vqs[index].poll);
+ vhost_poll_flush(&n->vqs[index].poll);
}
static void vhost_test_flush(struct vhost_test *n)
@@ -268,14 +277,14 @@ static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
return -EFAULT;
return vhost_test_run(n, test);
case VHOST_GET_FEATURES:
- features = VHOST_NET_FEATURES;
+ features = VHOST_FEATURES;
if (copy_to_user(featurep, &features, sizeof features))
return -EFAULT;
return 0;
case VHOST_SET_FEATURES:
if (copy_from_user(&features, featurep, sizeof features))
return -EFAULT;
- if (features & ~VHOST_NET_FEATURES)
+ if (features & ~VHOST_FEATURES)
return -EOPNOTSUPP;
return vhost_test_set_features(n, features);
case VHOST_RESET_OWNER:
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 60aa5ad09a2f..e58cf0001cee 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/cgroup.h>
+#include <linux/module.h>
#include "vhost.h"
@@ -66,6 +67,7 @@ void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn)
work->flushing = 0;
work->queue_seq = work->done_seq = 0;
}
+EXPORT_SYMBOL_GPL(vhost_work_init);
/* Init poll structure */
void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
@@ -79,6 +81,7 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
vhost_work_init(&poll->work, fn);
}
+EXPORT_SYMBOL_GPL(vhost_poll_init);
/* Start polling a file. We add ourselves to file's wait queue. The caller must
* keep a reference to a file until after vhost_poll_stop is called. */
@@ -101,6 +104,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file)
return ret;
}
+EXPORT_SYMBOL_GPL(vhost_poll_start);
/* Stop polling a file. After this function returns, it becomes safe to drop the
* file reference. You must also flush afterwards. */
@@ -111,6 +115,7 @@ void vhost_poll_stop(struct vhost_poll *poll)
poll->wqh = NULL;
}
}
+EXPORT_SYMBOL_GPL(vhost_poll_stop);
static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
unsigned seq)
@@ -123,7 +128,7 @@ static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
return left <= 0;
}
-static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
+void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
{
unsigned seq;
int flushing;
@@ -138,6 +143,7 @@ static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
spin_unlock_irq(&dev->work_lock);
BUG_ON(flushing < 0);
}
+EXPORT_SYMBOL_GPL(vhost_work_flush);
/* Flush any work that has been scheduled. When calling this, don't hold any
* locks that are also used by the callback. */
@@ -145,6 +151,7 @@ void vhost_poll_flush(struct vhost_poll *poll)
{
vhost_work_flush(poll->dev, &poll->work);
}
+EXPORT_SYMBOL_GPL(vhost_poll_flush);
void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
{
@@ -158,11 +165,13 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
}
spin_unlock_irqrestore(&dev->work_lock, flags);
}
+EXPORT_SYMBOL_GPL(vhost_work_queue);
void vhost_poll_queue(struct vhost_poll *poll)
{
vhost_work_queue(poll->dev, &poll->work);
}
+EXPORT_SYMBOL_GPL(vhost_poll_queue);
static void vhost_vq_reset(struct vhost_dev *dev,
struct vhost_virtqueue *vq)
@@ -251,17 +260,16 @@ static void vhost_vq_free_iovecs(struct vhost_virtqueue *vq)
/* Helper to allocate iovec buffers for all vqs. */
static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
{
+ struct vhost_virtqueue *vq;
int i;
for (i = 0; i < dev->nvqs; ++i) {
- dev->vqs[i]->indirect = kmalloc(sizeof *dev->vqs[i]->indirect *
- UIO_MAXIOV, GFP_KERNEL);
- dev->vqs[i]->log = kmalloc(sizeof *dev->vqs[i]->log * UIO_MAXIOV,
- GFP_KERNEL);
- dev->vqs[i]->heads = kmalloc(sizeof *dev->vqs[i]->heads *
- UIO_MAXIOV, GFP_KERNEL);
- if (!dev->vqs[i]->indirect || !dev->vqs[i]->log ||
- !dev->vqs[i]->heads)
+ vq = dev->vqs[i];
+ vq->indirect = kmalloc(sizeof *vq->indirect * UIO_MAXIOV,
+ GFP_KERNEL);
+ vq->log = kmalloc(sizeof *vq->log * UIO_MAXIOV, GFP_KERNEL);
+ vq->heads = kmalloc(sizeof *vq->heads * UIO_MAXIOV, GFP_KERNEL);
+ if (!vq->indirect || !vq->log || !vq->heads)
goto err_nomem;
}
return 0;
@@ -283,6 +291,7 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
long vhost_dev_init(struct vhost_dev *dev,
struct vhost_virtqueue **vqs, int nvqs)
{
+ struct vhost_virtqueue *vq;
int i;
dev->vqs = vqs;
@@ -297,19 +306,21 @@ long vhost_dev_init(struct vhost_dev *dev,
dev->worker = NULL;
for (i = 0; i < dev->nvqs; ++i) {
- dev->vqs[i]->log = NULL;
- dev->vqs[i]->indirect = NULL;
- dev->vqs[i]->heads = NULL;
- dev->vqs[i]->dev = dev;
- mutex_init(&dev->vqs[i]->mutex);
- vhost_vq_reset(dev, dev->vqs[i]);
- if (dev->vqs[i]->handle_kick)
- vhost_poll_init(&dev->vqs[i]->poll,
- dev->vqs[i]->handle_kick, POLLIN, dev);
+ vq = dev->vqs[i];
+ vq->log = NULL;
+ vq->indirect = NULL;
+ vq->heads = NULL;
+ vq->dev = dev;
+ mutex_init(&vq->mutex);
+ vhost_vq_reset(dev, vq);
+ if (vq->handle_kick)
+ vhost_poll_init(&vq->poll, vq->handle_kick,
+ POLLIN, dev);
}
return 0;
}
+EXPORT_SYMBOL_GPL(vhost_dev_init);
/* Caller should have device mutex */
long vhost_dev_check_owner(struct vhost_dev *dev)
@@ -317,6 +328,7 @@ long vhost_dev_check_owner(struct vhost_dev *dev)
/* Are you the owner? If not, I don't think you mean to do that */
return dev->mm == current->mm ? 0 : -EPERM;
}
+EXPORT_SYMBOL_GPL(vhost_dev_check_owner);
struct vhost_attach_cgroups_struct {
struct vhost_work work;
@@ -348,6 +360,7 @@ bool vhost_dev_has_owner(struct vhost_dev *dev)
{
return dev->mm;
}
+EXPORT_SYMBOL_GPL(vhost_dev_has_owner);
/* Caller should have device mutex */
long vhost_dev_set_owner(struct vhost_dev *dev)
@@ -391,11 +404,13 @@ err_worker:
err_mm:
return err;
}
+EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
struct vhost_memory *vhost_dev_reset_owner_prepare(void)
{
return kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL);
}
+EXPORT_SYMBOL_GPL(vhost_dev_reset_owner_prepare);
/* Caller should have device mutex */
void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_memory *memory)
@@ -406,6 +421,7 @@ void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_memory *memory)
memory->nregions = 0;
RCU_INIT_POINTER(dev->memory, memory);
}
+EXPORT_SYMBOL_GPL(vhost_dev_reset_owner);
void vhost_dev_stop(struct vhost_dev *dev)
{
@@ -418,6 +434,7 @@ void vhost_dev_stop(struct vhost_dev *dev)
}
}
}
+EXPORT_SYMBOL_GPL(vhost_dev_stop);
/* Caller should have device mutex if and only if locked is set */
void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
@@ -458,6 +475,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
mmput(dev->mm);
dev->mm = NULL;
}
+EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
{
@@ -543,6 +561,7 @@ int vhost_log_access_ok(struct vhost_dev *dev)
lockdep_is_held(&dev->mutex));
return memory_access_ok(dev, mp, 1);
}
+EXPORT_SYMBOL_GPL(vhost_log_access_ok);
/* Verify access for write logging. */
/* Caller should have vq mutex and device mutex */
@@ -568,6 +587,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq)
return vq_access_ok(vq->dev, vq->num, vq->desc, vq->avail, vq->used) &&
vq_log_access_ok(vq->dev, vq, vq->log_base);
}
+EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
{
@@ -797,6 +817,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
vhost_poll_flush(&vq->poll);
return r;
}
+EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
/* Caller must have device mutex */
long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
@@ -877,6 +898,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
done:
return r;
}
+EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
__u64 addr, __u32 len)
@@ -968,6 +990,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
BUG();
return 0;
}
+EXPORT_SYMBOL_GPL(vhost_log_write);
static int vhost_update_used_flags(struct vhost_virtqueue *vq)
{
@@ -1019,6 +1042,7 @@ int vhost_init_used(struct vhost_virtqueue *vq)
vq->signalled_used_valid = false;
return get_user(vq->last_used_idx, &vq->used->idx);
}
+EXPORT_SYMBOL_GPL(vhost_init_used);
static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
struct iovec iov[], int iov_size)
@@ -1295,12 +1319,14 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
BUG_ON(!(vq->used_flags & VRING_USED_F_NO_NOTIFY));
return head;
}
+EXPORT_SYMBOL_GPL(vhost_get_vq_desc);
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
void vhost_discard_vq_desc(struct vhost_virtqueue *vq, int n)
{
vq->last_avail_idx -= n;
}
+EXPORT_SYMBOL_GPL(vhost_discard_vq_desc);
/* After we've used one of their buffers, we tell them about it. We'll then
* want to notify the guest, using eventfd. */
@@ -1349,6 +1375,7 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
vq->signalled_used_valid = false;
return 0;
}
+EXPORT_SYMBOL_GPL(vhost_add_used);
static int __vhost_add_used_n(struct vhost_virtqueue *vq,
struct vring_used_elem *heads,
@@ -1418,6 +1445,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
}
return r;
}
+EXPORT_SYMBOL_GPL(vhost_add_used_n);
static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
@@ -1462,6 +1490,7 @@ void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (vq->call_ctx && vhost_notify(dev, vq))
eventfd_signal(vq->call_ctx, 1);
}
+EXPORT_SYMBOL_GPL(vhost_signal);
/* And here's the combo meal deal. Supersize me! */
void vhost_add_used_and_signal(struct vhost_dev *dev,
@@ -1471,6 +1500,7 @@ void vhost_add_used_and_signal(struct vhost_dev *dev,
vhost_add_used(vq, head, len);
vhost_signal(dev, vq);
}
+EXPORT_SYMBOL_GPL(vhost_add_used_and_signal);
/* multi-buffer version of vhost_add_used_and_signal */
void vhost_add_used_and_signal_n(struct vhost_dev *dev,
@@ -1480,6 +1510,7 @@ void vhost_add_used_and_signal_n(struct vhost_dev *dev,
vhost_add_used_n(vq, heads, count);
vhost_signal(dev, vq);
}
+EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n);
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
@@ -1517,6 +1548,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
return avail_idx != vq->avail_idx;
}
+EXPORT_SYMBOL_GPL(vhost_enable_notify);
/* We don't need to be notified again. */
void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
@@ -1533,3 +1565,21 @@ void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
&vq->used->flags, r);
}
}
+EXPORT_SYMBOL_GPL(vhost_disable_notify);
+
+static int __init vhost_init(void)
+{
+ return 0;
+}
+
+static void __exit vhost_exit(void)
+{
+}
+
+module_init(vhost_init);
+module_exit(vhost_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio");
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 64adcf99ff33..42298cd23c73 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -46,6 +46,8 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file);
void vhost_poll_stop(struct vhost_poll *poll);
void vhost_poll_flush(struct vhost_poll *poll);
void vhost_poll_queue(struct vhost_poll *poll);
+void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work);
+long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp);
struct vhost_log {
u64 addr;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 0098810df69d..1f572c00a1be 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -192,7 +192,8 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
* virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
* is true, we *have* to do it in this order
*/
- tell_host(vb, vb->deflate_vq);
+ if (vb->num_pfns != 0)
+ tell_host(vb, vb->deflate_vq);
mutex_unlock(&vb->balloon_lock);
release_pages_by_pfn(vb->pfns, vb->num_pfns);
}
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index a7ce73029f59..1aba255b5879 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -289,9 +289,9 @@ static void vp_free_vectors(struct virtio_device *vdev)
pci_disable_msix(vp_dev->pci_dev);
vp_dev->msix_enabled = 0;
- vp_dev->msix_vectors = 0;
}
+ vp_dev->msix_vectors = 0;
vp_dev->msix_used_vectors = 0;
kfree(vp_dev->msix_names);
vp_dev->msix_names = NULL;
@@ -309,6 +309,8 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
unsigned i, v;
int err = -ENOMEM;
+ vp_dev->msix_vectors = nvectors;
+
vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
GFP_KERNEL);
if (!vp_dev->msix_entries)
@@ -336,7 +338,6 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
err = -ENOSPC;
if (err)
goto error;
- vp_dev->msix_vectors = nvectors;
vp_dev->msix_enabled = 1;
/* Set the vector used for configuration */
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7460d349df59..362085d7ad8f 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -221,15 +221,6 @@ config DW_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called dw_wdt.
-config MPCORE_WATCHDOG
- tristate "MPcore watchdog"
- depends on HAVE_ARM_TWD
- help
- Watchdog timer embedded into the MPcore system.
-
- To compile this driver as a module, choose M here: the
- module will be called mpcore_wdt.
-
config EP93XX_WATCHDOG
tristate "EP93xx Watchdog"
depends on ARCH_EP93XX
@@ -291,7 +282,7 @@ config DAVINCI_WATCHDOG
config ORION_WATCHDOG
tristate "Orion watchdog"
- depends on ARCH_ORION5X || ARCH_KIRKWOOD
+ depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
@@ -1083,7 +1074,7 @@ config TXX9_WDT
config OCTEON_WDT
tristate "Cavium OCTEON SOC family Watchdog Timer"
- depends on CPU_CAVIUM_OCTEON
+ depends on CAVIUM_OCTEON_SOC
default y
select EXPORT_UASM if OCTEON_WDT = m
help
@@ -1109,6 +1100,17 @@ config BCM63XX_WDT
To compile this driver as a loadable module, choose M here.
The module will be called bcm63xx_wdt.
+config BCM2835_WDT
+ tristate "Broadcom BCM2835 hardware watchdog"
+ depends on ARCH_BCM2835
+ select WATCHDOG_CORE
+ help
+ Watchdog driver for the built in watchdog hardware in Broadcom
+ BCM2835 SoC.
+
+ To compile this driver as a loadable module, choose M here.
+ The module will be called bcm2835_wdt.
+
config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
@@ -1183,6 +1185,18 @@ config BOOKE_WDT_DEFAULT_TIMEOUT
The value can be overridden by the wdt_period command-line parameter.
+config MEN_A21_WDT
+ tristate "MEN A21 VME CPU Carrier Board Watchdog Timer"
+ select WATCHDOG_CORE
+ depends on GPIOLIB
+ help
+ Watchdog driver for MEN A21 VMEbus CPU Carrier Boards.
+
+ The driver can also be built as a module. If so, the module will be
+ called mena21_wdt.
+
+ If unsure select N here.
+
# PPC64 Architecture
config WATCHDOG_RTAS
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ec268995b261..2f26a0b47ddc 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -41,7 +41,6 @@ obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
-obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
@@ -54,6 +53,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
+obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -144,6 +144,7 @@ obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_PIKA_WDT) += pika_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
+obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o
# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 7a715e3e6828..b178e717ef09 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -321,13 +321,14 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
return -ENXIO;
}
- wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
+ wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x),
+ GFP_KERNEL);
if (!wdt) {
dev_dbg(&pdev->dev, "no memory for wdt structure\n");
return -ENOMEM;
}
- wdt->regs = ioremap(regs->start, resource_size(regs));
+ wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
if (!wdt->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
@@ -342,7 +343,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "CPU must be reset with external "
"reset or POR due to silicon errata.\n");
ret = -EIO;
- goto err_iounmap;
+ goto err_free;
} else {
wdt->users = 0;
}
@@ -364,7 +365,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
ret = misc_register(&wdt->miscdev);
if (ret) {
dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
- goto err_register;
+ goto err_free;
}
dev_info(&pdev->dev,
@@ -373,12 +374,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
return 0;
-err_register:
- platform_set_drvdata(pdev, NULL);
-err_iounmap:
- iounmap(wdt->regs);
err_free:
- kfree(wdt);
wdt = NULL;
return ret;
}
@@ -391,10 +387,7 @@ static int __exit at32_wdt_remove(struct platform_device *pdev)
at32_wdt_stop();
misc_deregister(&wdt->miscdev);
- iounmap(wdt->regs);
- kfree(wdt);
wdt = NULL;
- platform_set_drvdata(pdev, NULL);
}
return 0;
}
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
new file mode 100644
index 000000000000..61566fc47f84
--- /dev/null
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -0,0 +1,189 @@
+/*
+ * Watchdog driver for Broadcom BCM2835
+ *
+ * "bcm2708_wdog" driver written by Luke Diamand that was obtained from
+ * branch "rpi-3.6.y" of git://github.com/raspberrypi/linux.git was used
+ * as a hardware reference for the Broadcom BCM2835 watchdog timer.
+ *
+ * Copyright (C) 2013 Lubomir Rintel <lkundrak@v3.sk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/miscdevice.h>
+
+#define PM_RSTC 0x1c
+#define PM_WDOG 0x24
+
+#define PM_PASSWORD 0x5a000000
+
+#define PM_WDOG_TIME_SET 0x000fffff
+#define PM_RSTC_WRCFG_CLR 0xffffffcf
+#define PM_RSTC_WRCFG_SET 0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
+#define PM_RSTC_RESET 0x00000102
+
+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
+
+struct bcm2835_wdt {
+ void __iomem *base;
+ spinlock_t lock;
+};
+
+static unsigned int heartbeat;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+
+static int bcm2835_wdt_start(struct watchdog_device *wdog)
+{
+ struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+ uint32_t cur;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdt->lock, flags);
+
+ writel_relaxed(PM_PASSWORD | (SECS_TO_WDOG_TICKS(wdog->timeout) &
+ PM_WDOG_TIME_SET), wdt->base + PM_WDOG);
+ cur = readl_relaxed(wdt->base + PM_RSTC);
+ writel_relaxed(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) |
+ PM_RSTC_WRCFG_FULL_RESET, wdt->base + PM_RSTC);
+
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ return 0;
+}
+
+static int bcm2835_wdt_stop(struct watchdog_device *wdog)
+{
+ struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+ writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC);
+ dev_info(wdog->dev, "Watchdog timer stopped");
+ return 0;
+}
+
+static int bcm2835_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
+{
+ wdog->timeout = t;
+ return 0;
+}
+
+static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
+{
+ struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+ uint32_t ret = readl_relaxed(wdt->base + PM_WDOG);
+ return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
+}
+
+static struct watchdog_ops bcm2835_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = bcm2835_wdt_start,
+ .stop = bcm2835_wdt_stop,
+ .set_timeout = bcm2835_wdt_set_timeout,
+ .get_timeleft = bcm2835_wdt_get_timeleft,
+};
+
+static struct watchdog_info bcm2835_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .identity = "Broadcom BCM2835 Watchdog timer",
+};
+
+static struct watchdog_device bcm2835_wdt_wdd = {
+ .info = &bcm2835_wdt_info,
+ .ops = &bcm2835_wdt_ops,
+ .min_timeout = 1,
+ .max_timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+ .timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+};
+
+static int bcm2835_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct bcm2835_wdt *wdt;
+ int err;
+
+ wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
+ if (!wdt) {
+ dev_err(dev, "Failed to allocate memory for watchdog device");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, wdt);
+
+ spin_lock_init(&wdt->lock);
+
+ wdt->base = of_iomap(np, 0);
+ if (!wdt->base) {
+ dev_err(dev, "Failed to remap watchdog regs");
+ return -ENODEV;
+ }
+
+ watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
+ watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
+ watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout);
+ err = watchdog_register_device(&bcm2835_wdt_wdd);
+ if (err) {
+ dev_err(dev, "Failed to register watchdog device");
+ iounmap(wdt->base);
+ return err;
+ }
+
+ dev_info(dev, "Broadcom BCM2835 watchdog timer");
+ return 0;
+}
+
+static int bcm2835_wdt_remove(struct platform_device *pdev)
+{
+ struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+
+ watchdog_unregister_device(&bcm2835_wdt_wdd);
+ iounmap(wdt->base);
+
+ return 0;
+}
+
+static void bcm2835_wdt_shutdown(struct platform_device *pdev)
+{
+ bcm2835_wdt_stop(&bcm2835_wdt_wdd);
+}
+
+static const struct of_device_id bcm2835_wdt_of_match[] = {
+ { .compatible = "brcm,bcm2835-pm-wdt", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
+
+static struct platform_driver bcm2835_wdt_driver = {
+ .probe = bcm2835_wdt_probe,
+ .remove = bcm2835_wdt_remove,
+ .shutdown = bcm2835_wdt_shutdown,
+ .driver = {
+ .name = "bcm2835-wdt",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_wdt_of_match,
+ },
+};
+module_platform_driver(bcm2835_wdt_driver);
+
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
+
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
index b2b80d4ac818..a14a58d9d110 100644
--- a/drivers/watchdog/bcm63xx_wdt.c
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
@@ -249,7 +250,8 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
return -ENODEV;
}
- bcm63xx_wdt_device.regs = ioremap_nocache(r->start, resource_size(r));
+ bcm63xx_wdt_device.regs = devm_ioremap_nocache(&pdev->dev, r->start,
+ resource_size(r));
if (!bcm63xx_wdt_device.regs) {
dev_err(&pdev->dev, "failed to remap I/O resources\n");
return -ENXIO;
@@ -258,7 +260,7 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register wdt timer isr\n");
- goto unmap;
+ return ret;
}
if (bcm63xx_wdt_settimeout(wdt_time)) {
@@ -281,8 +283,6 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
unregister_timer:
bcm63xx_timer_unregister(TIMER_WDT_ID);
-unmap:
- iounmap(bcm63xx_wdt_device.regs);
return ret;
}
@@ -293,7 +293,6 @@ static int bcm63xx_wdt_remove(struct platform_device *pdev)
misc_deregister(&bcm63xx_wdt_miscdev);
bcm63xx_timer_unregister(TIMER_WDT_ID);
- iounmap(bcm63xx_wdt_device.regs);
return 0;
}
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 70387582843f..213225edd059 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -621,7 +621,7 @@ static int cpwd_probe(struct platform_device *op)
WD_BADMODEL);
}
- dev_set_drvdata(&op->dev, p);
+ platform_set_drvdata(op, p);
cpwd_device = p;
err = 0;
@@ -642,7 +642,7 @@ out_free:
static int cpwd_remove(struct platform_device *op)
{
- struct cpwd *p = dev_get_drvdata(&op->dev);
+ struct cpwd *p = platform_get_drvdata(op);
int i;
for (i = 0; i < WD_NUMDEVS; i++) {
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index 367445009c64..f09c54e9686f 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -215,14 +215,14 @@ static int da9052_wdt_probe(struct platform_device *pdev)
goto err;
}
- dev_set_drvdata(&pdev->dev, driver_data);
+ platform_set_drvdata(pdev, driver_data);
err:
return ret;
}
static int da9052_wdt_remove(struct platform_device *pdev)
{
- struct da9052_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+ struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
watchdog_unregister_device(&driver_data->wdt);
kref_put(&driver_data->kref, da9052_wdt_release_resources);
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
index f5ad10546fc9..575f37a965a4 100644
--- a/drivers/watchdog/da9055_wdt.c
+++ b/drivers/watchdog/da9055_wdt.c
@@ -174,7 +174,7 @@ static int da9055_wdt_probe(struct platform_device *pdev)
goto err;
}
- dev_set_drvdata(&pdev->dev, driver_data);
+ platform_set_drvdata(pdev, driver_data);
ret = watchdog_register_device(&driver_data->wdt);
if (ret != 0)
@@ -187,7 +187,7 @@ err:
static int da9055_wdt_remove(struct platform_device *pdev)
{
- struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+ struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
watchdog_unregister_device(&driver_data->wdt);
kref_put(&driver_data->kref, da9055_wdt_release_resources);
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 203766989382..e621098bf663 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -154,8 +154,8 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
return nonseekable_open(inode, filp);
}
-ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len,
- loff_t *offset)
+static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *offset)
{
if (!len)
return 0;
@@ -305,13 +305,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
if (IS_ERR(dw_wdt.regs))
return PTR_ERR(dw_wdt.regs);
- dw_wdt.clk = clk_get(&pdev->dev, NULL);
+ dw_wdt.clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dw_wdt.clk))
return PTR_ERR(dw_wdt.clk);
ret = clk_enable(dw_wdt.clk);
if (ret)
- goto out_put_clk;
+ return ret;
spin_lock_init(&dw_wdt.lock);
@@ -327,8 +327,6 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
out_disable_clk:
clk_disable(dw_wdt.clk);
-out_put_clk:
- clk_put(dw_wdt.clk);
return ret;
}
@@ -338,7 +336,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev)
misc_deregister(&dw_wdt_miscdev);
clk_disable(dw_wdt.clk);
- clk_put(dw_wdt.clk);
return 0;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 11796b9b864e..de7e4f497222 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -39,7 +39,7 @@
#endif /* CONFIG_HPWDT_NMI_DECODING */
#include <asm/nmi.h>
-#define HPWDT_VERSION "1.3.1"
+#define HPWDT_VERSION "1.3.2"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
@@ -148,6 +148,7 @@ struct cmn_registers {
static unsigned int hpwdt_nmi_decoding;
static unsigned int allow_kdump = 1;
static unsigned int is_icru;
+static unsigned int is_uefi;
static DEFINE_SPINLOCK(rom_lock);
static void *cru_rom_addr;
static struct cmn_registers cmn_regs;
@@ -484,7 +485,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
goto out;
spin_lock_irqsave(&rom_lock, rom_pl);
- if (!die_nmi_called && !is_icru)
+ if (!die_nmi_called && !is_icru && !is_uefi)
asminline_call(&cmn_regs, cru_rom_addr);
die_nmi_called = 1;
spin_unlock_irqrestore(&rom_lock, rom_pl);
@@ -492,7 +493,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (allow_kdump)
hpwdt_stop();
- if (!is_icru) {
+ if (!is_icru && !is_uefi) {
if (cmn_regs.u1.ral == 0) {
panic("An NMI occurred, "
"but unable to determine source.\n");
@@ -679,6 +680,8 @@ static void dmi_find_icru(const struct dmi_header *dm, void *dummy)
smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
if (smbios_proliant_ptr->misc_features & 0x01)
is_icru = 1;
+ if (smbios_proliant_ptr->misc_features & 0x408)
+ is_uefi = 1;
}
}
@@ -697,7 +700,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
* the old cru detect code.
*/
dmi_walk(dmi_find_icru, NULL);
- if (!is_icru) {
+ if (!is_icru && !is_uefi) {
/*
* We need to map the ROM to get the CRU service.
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 62946c2cb4f8..693ac3f4de5a 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -261,7 +261,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
if (IS_ERR(imx2_wdt.base))
return PTR_ERR(imx2_wdt.base);
- imx2_wdt.clk = clk_get(&pdev->dev, NULL);
+ imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(imx2_wdt.clk)) {
dev_err(&pdev->dev, "can't get Watchdog clock\n");
return PTR_ERR(imx2_wdt.clk);
@@ -286,7 +286,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
fail:
imx2_wdt_miscdev.parent = NULL;
- clk_put(imx2_wdt.clk);
return ret;
}
@@ -299,8 +298,7 @@ static int __exit imx2_wdt_remove(struct platform_device *pdev)
dev_crit(imx2_wdt_miscdev.parent,
"Device removed: Expect reboot!\n");
- } else
- clk_put(imx2_wdt.clk);
+ }
imx2_wdt_miscdev.parent = NULL;
return 0;
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 1cb25f69a96d..d1afdf684c18 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -177,7 +177,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
goto err_out;
}
- drvdata->rtc_clk = clk_get(NULL, "rtc");
+ drvdata->rtc_clk = clk_get(&pdev->dev, "rtc");
if (IS_ERR(drvdata->rtc_clk)) {
dev_err(&pdev->dev, "cannot find RTC clock\n");
ret = PTR_ERR(drvdata->rtc_clk);
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
new file mode 100644
index 000000000000..96dbba980579
--- /dev/null
+++ b/drivers/watchdog/mena21_wdt.c
@@ -0,0 +1,270 @@
+/*
+ * Watchdog driver for the A21 VME CPU Boards
+ *
+ * Copyright (C) 2013 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ * 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
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define NUM_GPIOS 6
+
+enum a21_wdt_gpios {
+ GPIO_WD_ENAB,
+ GPIO_WD_FAST,
+ GPIO_WD_TRIG,
+ GPIO_WD_RST0,
+ GPIO_WD_RST1,
+ GPIO_WD_RST2,
+};
+
+struct a21_wdt_drv {
+ struct watchdog_device wdt;
+ struct mutex lock;
+ unsigned gpios[NUM_GPIOS];
+};
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv)
+{
+ int reset = 0;
+
+ reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0;
+ reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0;
+ reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0;
+
+ return reset;
+}
+
+static int a21_wdt_start(struct watchdog_device *wdt)
+{
+ struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+ mutex_lock(&drv->lock);
+
+ gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1);
+
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+
+static int a21_wdt_stop(struct watchdog_device *wdt)
+{
+ struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+ mutex_lock(&drv->lock);
+
+ gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
+
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+
+static int a21_wdt_ping(struct watchdog_device *wdt)
+{
+ struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+ mutex_lock(&drv->lock);
+
+ gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0);
+ ndelay(10);
+ gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1);
+
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+
+static int a21_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int timeout)
+{
+ struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+ if (timeout != 1 && timeout != 30) {
+ dev_err(wdt->dev, "Only 1 and 30 allowed as timeout\n");
+ return -EINVAL;
+ }
+
+ if (timeout == 30 && wdt->timeout == 1) {
+ dev_err(wdt->dev,
+ "Transition from fast to slow mode not allowed\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&drv->lock);
+
+ if (timeout == 1)
+ gpio_set_value(drv->gpios[GPIO_WD_FAST], 1);
+ else
+ gpio_set_value(drv->gpios[GPIO_WD_FAST], 0);
+
+ wdt->timeout = timeout;
+
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+
+static const struct watchdog_info a21_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "MEN A21 Watchdog",
+};
+
+static const struct watchdog_ops a21_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = a21_wdt_start,
+ .stop = a21_wdt_stop,
+ .ping = a21_wdt_ping,
+ .set_timeout = a21_wdt_set_timeout,
+};
+
+static struct watchdog_device a21_wdt = {
+ .info = &a21_wdt_info,
+ .ops = &a21_wdt_ops,
+ .min_timeout = 1,
+ .max_timeout = 30,
+};
+
+static int a21_wdt_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ struct a21_wdt_drv *drv;
+ unsigned int reset = 0;
+ int num_gpios;
+ int ret;
+ int i;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(struct a21_wdt_drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ /* Fill GPIO pin array */
+ node = pdev->dev.of_node;
+
+ num_gpios = of_gpio_count(node);
+ if (num_gpios != NUM_GPIOS) {
+ dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d",
+ num_gpios, NUM_GPIOS);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < num_gpios; i++) {
+ int val;
+
+ val = of_get_gpio(node, i);
+ if (val < 0)
+ return val;
+
+ drv->gpios[i] = val;
+ }
+
+ /* Request the used GPIOs */
+ for (i = 0; i < num_gpios; i++) {
+ ret = devm_gpio_request(&pdev->dev, drv->gpios[i],
+ "MEN A21 Watchdog");
+ if (ret)
+ return ret;
+
+ if (i < GPIO_WD_RST0)
+ ret = gpio_direction_output(drv->gpios[i],
+ gpio_get_value(drv->gpios[i]));
+ else /* GPIO_WD_RST[0..2] are inputs */
+ ret = gpio_direction_input(drv->gpios[i]);
+ if (ret)
+ return ret;
+ }
+
+ mutex_init(&drv->lock);
+ watchdog_init_timeout(&a21_wdt, 30, &pdev->dev);
+ watchdog_set_nowayout(&a21_wdt, nowayout);
+ watchdog_set_drvdata(&a21_wdt, drv);
+
+ reset = a21_wdt_get_bootstatus(drv);
+ if (reset == 2)
+ a21_wdt.bootstatus |= WDIOF_EXTERN1;
+ else if (reset == 4)
+ a21_wdt.bootstatus |= WDIOF_CARDRESET;
+ else if (reset == 5)
+ a21_wdt.bootstatus |= WDIOF_POWERUNDER;
+ else if (reset == 7)
+ a21_wdt.bootstatus |= WDIOF_EXTERN2;
+
+ ret = watchdog_register_device(&a21_wdt);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot register watchdog device\n");
+ goto err_register_wd;
+ }
+
+ dev_set_drvdata(&pdev->dev, drv);
+
+ dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n");
+
+ return 0;
+
+err_register_wd:
+ mutex_destroy(&drv->lock);
+
+ return ret;
+}
+
+static int a21_wdt_remove(struct platform_device *pdev)
+{
+ struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
+
+ dev_warn(&pdev->dev,
+ "Unregistering A21 watchdog driver, board may reboot\n");
+
+ watchdog_unregister_device(&drv->wdt);
+
+ mutex_destroy(&drv->lock);
+
+ return 0;
+}
+
+static void a21_wdt_shutdown(struct platform_device *pdev)
+{
+ struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
+
+ gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
+}
+
+static const struct of_device_id a21_wdt_ids[] = {
+ { .compatible = "men,a021-wdt" },
+ { },
+};
+
+static struct platform_driver a21_wdt_driver = {
+ .probe = a21_wdt_probe,
+ .remove = a21_wdt_remove,
+ .shutdown = a21_wdt_shutdown,
+ .driver = {
+ .name = "a21-watchdog",
+ .of_match_table = a21_wdt_ids,
+ },
+};
+
+module_platform_driver(a21_wdt_driver);
+
+MODULE_AUTHOR("MEN Mikro Elektronik");
+MODULE_DESCRIPTION("MEN A21 Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:a21-watchdog");
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
deleted file mode 100644
index 233cfadcb21f..000000000000
--- a/drivers/watchdog/mpcore_wdt.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Watchdog driver for the mpcore watchdog timer
- *
- * (c) Copyright 2004 ARM Limited
- *
- * Based on the SoftDog driver:
- * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
- * 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.
- *
- * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
- *
- * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/fs.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-
-#include <asm/smp_twd.h>
-
-struct mpcore_wdt {
- unsigned long timer_alive;
- struct device *dev;
- void __iomem *base;
- int irq;
- unsigned int perturb;
- char expect_close;
-};
-
-static struct platform_device *mpcore_wdt_pdev;
-static DEFINE_SPINLOCK(wdt_lock);
-
-#define TIMER_MARGIN 60
-static int mpcore_margin = TIMER_MARGIN;
-module_param(mpcore_margin, int, 0);
-MODULE_PARM_DESC(mpcore_margin,
- "MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
- __MODULE_STRING(TIMER_MARGIN) ")");
-
-static bool nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout,
- "Watchdog cannot be stopped once started (default="
- __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-#define ONLY_TESTING 0
-static int mpcore_noboot = ONLY_TESTING;
-module_param(mpcore_noboot, int, 0);
-MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, "
- "set to 1 to ignore reboots, 0 to reboot (default="
- __MODULE_STRING(ONLY_TESTING) ")");
-
-/*
- * This is the interrupt handler. Note that we only use this
- * in testing mode, so don't actually do a reboot here.
- */
-static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
-{
- struct mpcore_wdt *wdt = arg;
-
- /* Check it really was our interrupt */
- if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
- dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
- /* Clear the interrupt on the watchdog */
- writel(1, wdt->base + TWD_WDOG_INTSTAT);
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-/*
- * mpcore_wdt_keepalive - reload the timer
- *
- * Note that the spec says a DIFFERENT value must be written to the reload
- * register each time. The "perturb" variable deals with this by adding 1
- * to the count every other time the function is called.
- */
-static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
-{
- unsigned long count;
-
- spin_lock(&wdt_lock);
- /* Assume prescale is set to 256 */
- count = __raw_readl(wdt->base + TWD_WDOG_COUNTER);
- count = (0xFFFFFFFFU - count) * (HZ / 5);
- count = (count / 256) * mpcore_margin;
-
- /* Reload the counter */
- writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
- wdt->perturb = wdt->perturb ? 0 : 1;
- spin_unlock(&wdt_lock);
-}
-
-static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
-{
- spin_lock(&wdt_lock);
- writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
- writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
- writel(0x0, wdt->base + TWD_WDOG_CONTROL);
- spin_unlock(&wdt_lock);
-}
-
-static void mpcore_wdt_start(struct mpcore_wdt *wdt)
-{
- dev_info(wdt->dev, "enabling watchdog\n");
-
- /* This loads the count register but does NOT start the count yet */
- mpcore_wdt_keepalive(wdt);
-
- if (mpcore_noboot) {
- /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
- writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
- } else {
- /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
- writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
- }
-}
-
-static int mpcore_wdt_set_heartbeat(int t)
-{
- if (t < 0x0001 || t > 0xFFFF)
- return -EINVAL;
-
- mpcore_margin = t;
- return 0;
-}
-
-/*
- * /dev/watchdog handling
- */
-static int mpcore_wdt_open(struct inode *inode, struct file *file)
-{
- struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev);
-
- if (test_and_set_bit(0, &wdt->timer_alive))
- return -EBUSY;
-
- if (nowayout)
- __module_get(THIS_MODULE);
-
- file->private_data = wdt;
-
- /*
- * Activate timer
- */
- mpcore_wdt_start(wdt);
-
- return nonseekable_open(inode, file);
-}
-
-static int mpcore_wdt_release(struct inode *inode, struct file *file)
-{
- struct mpcore_wdt *wdt = file->private_data;
-
- /*
- * Shut off the timer.
- * Lock it in if it's a module and we set nowayout
- */
- if (wdt->expect_close == 42)
- mpcore_wdt_stop(wdt);
- else {
- dev_crit(wdt->dev,
- "unexpected close, not stopping watchdog!\n");
- mpcore_wdt_keepalive(wdt);
- }
- clear_bit(0, &wdt->timer_alive);
- wdt->expect_close = 0;
- return 0;
-}
-
-static ssize_t mpcore_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
-{
- struct mpcore_wdt *wdt = file->private_data;
-
- /*
- * Refresh the timer.
- */
- if (len) {
- if (!nowayout) {
- size_t i;
-
- /* In case it was set long ago */
- wdt->expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- wdt->expect_close = 42;
- }
- }
- mpcore_wdt_keepalive(wdt);
- }
- return len;
-}
-
-static const struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
- .identity = "MPcore Watchdog",
-};
-
-static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct mpcore_wdt *wdt = file->private_data;
- int ret;
- union {
- struct watchdog_info ident;
- int i;
- } uarg;
-
- if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
- if (ret)
- return -EFAULT;
- }
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- uarg.ident = ident;
- ret = 0;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- uarg.i = 0;
- ret = 0;
- break;
-
- case WDIOC_SETOPTIONS:
- ret = -EINVAL;
- if (uarg.i & WDIOS_DISABLECARD) {
- mpcore_wdt_stop(wdt);
- ret = 0;
- }
- if (uarg.i & WDIOS_ENABLECARD) {
- mpcore_wdt_start(wdt);
- ret = 0;
- }
- break;
-
- case WDIOC_KEEPALIVE:
- mpcore_wdt_keepalive(wdt);
- ret = 0;
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = mpcore_wdt_set_heartbeat(uarg.i);
- if (ret)
- break;
-
- mpcore_wdt_keepalive(wdt);
- /* Fall */
- case WDIOC_GETTIMEOUT:
- uarg.i = mpcore_margin;
- ret = 0;
- break;
-
- default:
- return -ENOTTY;
- }
-
- if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
- ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
- if (ret)
- ret = -EFAULT;
- }
- return ret;
-}
-
-/*
- * System shutdown handler. Turn off the watchdog if we're
- * restarting or halting the system.
- */
-static void mpcore_wdt_shutdown(struct platform_device *pdev)
-{
- struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
-
- if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
- mpcore_wdt_stop(wdt);
-}
-
-/*
- * Kernel Interfaces
- */
-static const struct file_operations mpcore_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = mpcore_wdt_write,
- .unlocked_ioctl = mpcore_wdt_ioctl,
- .open = mpcore_wdt_open,
- .release = mpcore_wdt_release,
-};
-
-static struct miscdevice mpcore_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &mpcore_wdt_fops,
-};
-
-static int mpcore_wdt_probe(struct platform_device *pdev)
-{
- struct mpcore_wdt *wdt;
- struct resource *res;
- int ret;
-
- /* We only accept one device, and it must have an id of -1 */
- if (pdev->id != -1)
- return -ENODEV;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL);
- if (!wdt)
- return -ENOMEM;
-
- wdt->dev = &pdev->dev;
- wdt->irq = platform_get_irq(pdev, 0);
- if (wdt->irq >= 0) {
- ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
- "mpcore_wdt", wdt);
- if (ret) {
- dev_err(wdt->dev,
- "cannot register IRQ%d for watchdog\n",
- wdt->irq);
- return ret;
- }
- }
-
- wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res));
- if (!wdt->base)
- return -ENOMEM;
-
- mpcore_wdt_miscdev.parent = &pdev->dev;
- ret = misc_register(&mpcore_wdt_miscdev);
- if (ret) {
- dev_err(wdt->dev,
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
- return ret;
- }
-
- mpcore_wdt_stop(wdt);
- platform_set_drvdata(pdev, wdt);
- mpcore_wdt_pdev = pdev;
-
- return 0;
-}
-
-static int mpcore_wdt_remove(struct platform_device *pdev)
-{
- platform_set_drvdata(pdev, NULL);
-
- misc_deregister(&mpcore_wdt_miscdev);
-
- mpcore_wdt_pdev = NULL;
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg)
-{
- struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
- mpcore_wdt_stop(wdt); /* Turn the WDT off */
- return 0;
-}
-
-static int mpcore_wdt_resume(struct platform_device *pdev)
-{
- struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
- /* re-activate timer */
- if (test_bit(0, &wdt->timer_alive))
- mpcore_wdt_start(wdt);
- return 0;
-}
-#else
-#define mpcore_wdt_suspend NULL
-#define mpcore_wdt_resume NULL
-#endif
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpcore_wdt");
-
-static struct platform_driver mpcore_wdt_driver = {
- .probe = mpcore_wdt_probe,
- .remove = mpcore_wdt_remove,
- .suspend = mpcore_wdt_suspend,
- .resume = mpcore_wdt_resume,
- .shutdown = mpcore_wdt_shutdown,
- .driver = {
- .owner = THIS_MODULE,
- .name = "mpcore_wdt",
- },
-};
-
-static int __init mpcore_wdt_init(void)
-{
- /*
- * Check that the margin value is within it's range;
- * if not reset to the default
- */
- if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
- mpcore_wdt_set_heartbeat(TIMER_MARGIN);
- pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
- TIMER_MARGIN);
- }
-
- pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n",
- mpcore_noboot, mpcore_margin, nowayout);
-
- return platform_driver_register(&mpcore_wdt_driver);
-}
-
-static void __exit mpcore_wdt_exit(void)
-{
- platform_driver_unregister(&mpcore_wdt_driver);
-}
-
-module_init(mpcore_wdt_init);
-module_exit(mpcore_wdt_exit);
-
-MODULE_AUTHOR("ARM Limited");
-MODULE_DESCRIPTION("MPcore Watchdog Device Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 14dab6ff87aa..b4341110ad4f 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -209,7 +209,7 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
int ret;
mtx1_wdt_device.gpio = pdev->resource[0].start;
- ret = gpio_request_one(mtx1_wdt_device.gpio,
+ ret = devm_gpio_request_one(&pdev->dev, mtx1_wdt_device.gpio,
GPIOF_OUT_INIT_HIGH, "mtx1-wdt");
if (ret < 0) {
dev_err(&pdev->dev, "failed to request gpio");
@@ -241,7 +241,6 @@ static int mtx1_wdt_remove(struct platform_device *pdev)
wait_for_completion(&mtx1_wdt_device.stop);
}
- gpio_free(mtx1_wdt_device.gpio);
misc_deregister(&mtx1_wdt_misc);
return 0;
}
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index c7fb878ca493..e4cf98019265 100644
--- a/drivers/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -276,7 +276,7 @@ static int mv64x60_wdt_probe(struct platform_device *dev)
if (!r)
return -ENODEV;
- mv64x60_wdt_regs = ioremap(r->start, resource_size(r));
+ mv64x60_wdt_regs = devm_ioremap(&dev->dev, r->start, resource_size(r));
if (mv64x60_wdt_regs == NULL)
return -ENOMEM;
@@ -293,8 +293,6 @@ static int mv64x60_wdt_remove(struct platform_device *dev)
mv64x60_wdt_handler_disable();
- iounmap(mv64x60_wdt_regs);
-
return 0;
}
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c
index 04c45a102992..e2b6d2cf5c9d 100644
--- a/drivers/watchdog/nuc900_wdt.c
+++ b/drivers/watchdog/nuc900_wdt.c
@@ -61,7 +61,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
struct nuc900_wdt {
- struct resource *res;
struct clk *wdt_clock;
struct platform_device *pdev;
void __iomem *wdt_base;
@@ -244,9 +243,11 @@ static struct miscdevice nuc900wdt_miscdev = {
static int nuc900wdt_probe(struct platform_device *pdev)
{
+ struct resource *res;
int ret = 0;
- nuc900_wdt = kzalloc(sizeof(struct nuc900_wdt), GFP_KERNEL);
+ nuc900_wdt = devm_kzalloc(&pdev->dev, sizeof(*nuc900_wdt),
+ GFP_KERNEL);
if (!nuc900_wdt)
return -ENOMEM;
@@ -254,33 +255,20 @@ static int nuc900wdt_probe(struct platform_device *pdev)
spin_lock_init(&nuc900_wdt->wdt_lock);
- nuc900_wdt->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (nuc900_wdt->res == NULL) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
dev_err(&pdev->dev, "no memory resource specified\n");
- ret = -ENOENT;
- goto err_get;
+ return -ENOENT;
}
- if (!request_mem_region(nuc900_wdt->res->start,
- resource_size(nuc900_wdt->res), pdev->name)) {
- dev_err(&pdev->dev, "failed to get memory region\n");
- ret = -ENOENT;
- goto err_get;
- }
-
- nuc900_wdt->wdt_base = ioremap(nuc900_wdt->res->start,
- resource_size(nuc900_wdt->res));
- if (nuc900_wdt->wdt_base == NULL) {
- dev_err(&pdev->dev, "failed to ioremap() region\n");
- ret = -EINVAL;
- goto err_req;
- }
+ nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nuc900_wdt->wdt_base))
+ return PTR_ERR(nuc900_wdt->wdt_base);
- nuc900_wdt->wdt_clock = clk_get(&pdev->dev, NULL);
+ nuc900_wdt->wdt_clock = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nuc900_wdt->wdt_clock)) {
dev_err(&pdev->dev, "failed to find watchdog clock source\n");
- ret = PTR_ERR(nuc900_wdt->wdt_clock);
- goto err_map;
+ return PTR_ERR(nuc900_wdt->wdt_clock);
}
clk_enable(nuc900_wdt->wdt_clock);
@@ -298,14 +286,6 @@ static int nuc900wdt_probe(struct platform_device *pdev)
err_clk:
clk_disable(nuc900_wdt->wdt_clock);
- clk_put(nuc900_wdt->wdt_clock);
-err_map:
- iounmap(nuc900_wdt->wdt_base);
-err_req:
- release_mem_region(nuc900_wdt->res->start,
- resource_size(nuc900_wdt->res));
-err_get:
- kfree(nuc900_wdt);
return ret;
}
@@ -314,14 +294,6 @@ static int nuc900wdt_remove(struct platform_device *pdev)
misc_deregister(&nuc900wdt_miscdev);
clk_disable(nuc900_wdt->wdt_clock);
- clk_put(nuc900_wdt->wdt_clock);
-
- iounmap(nuc900_wdt->wdt_base);
-
- release_mem_region(nuc900_wdt->res->start,
- resource_size(nuc900_wdt->res));
-
- kfree(nuc900_wdt);
return 0;
}
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 2761ddb08501..4dd281f2c33f 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -1,23 +1,13 @@
/*
-* of_xilinx_wdt.c 1.01 A Watchdog Device Driver for Xilinx xps_timebase_wdt
-*
-* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.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.
-*
-* -----------------------
-* 30-May-2011 Alejandro Cabrera <aldaya@gmail.com>
-* - If "xlnx,wdt-enable-once" wasn't found on device tree the
-* module will use CONFIG_WATCHDOG_NOWAYOUT
-* - If the device tree parameters ("clock-frequency" and
-* "xlnx,wdt-interval") wasn't found the driver won't
-* know the wdt reset interval
-*/
+ * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
+ *
+ * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.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.
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -394,6 +384,7 @@ static int xwdt_remove(struct platform_device *dev)
/* Match table for of_platform binding */
static struct of_device_id xwdt_of_match[] = {
+ { .compatible = "xlnx,xps-timebase-wdt-1.00.a", },
{ .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
{},
};
@@ -413,5 +404,5 @@ module_platform_driver(xwdt_driver);
MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
MODULE_DESCRIPTION("Xilinx Watchdog driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index da577980d390..4ea5fcccac02 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -38,6 +38,9 @@
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
+#define WDT_RESET_OUT_EN BIT(1)
+#define WDT_INT_REQ BIT(3)
+
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
static unsigned int wdt_max_duration; /* (seconds) */
@@ -67,9 +70,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
/* Clear watchdog timer interrupt */
- reg = readl(BRIDGE_CAUSE);
- reg &= ~WDT_INT_REQ;
- writel(reg, BRIDGE_CAUSE);
+ writel(~WDT_INT_REQ, BRIDGE_CAUSE);
/* Enable watchdog timer */
reg = readl(wdt_reg + TIMER_CTRL);
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index a3684a30eb69..b30bd430f591 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -159,13 +159,13 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt_base))
return PTR_ERR(wdt_base);
- wdt_clk = clk_get(&pdev->dev, NULL);
+ wdt_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(wdt_clk))
return PTR_ERR(wdt_clk);
ret = clk_enable(wdt_clk);
if (ret)
- goto out;
+ return ret;
pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
WDIOF_CARDRESET : 0;
@@ -186,8 +186,6 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
disable_clk:
clk_disable(wdt_clk);
-out:
- clk_put(wdt_clk);
return ret;
}
@@ -196,7 +194,6 @@ static int pnx4008_wdt_remove(struct platform_device *pdev)
watchdog_unregister_device(&pnx4008_wdd);
clk_disable(wdt_clk);
- clk_put(wdt_clk);
return 0;
}
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index f78bc008cbb7..9cf6bc7a234f 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h> /* For platform_driver framework */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
+#include <linux/io.h> /* For devm_ioremap_nocache */
#include <asm/mach-rc32434/integ.h> /* For the Watchdog registers */
@@ -271,7 +272,7 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
return -ENODEV;
}
- wdt_reg = ioremap_nocache(r->start, resource_size(r));
+ wdt_reg = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
if (!wdt_reg) {
pr_err("failed to remap I/O resources\n");
return -ENXIO;
@@ -293,23 +294,18 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
ret = misc_register(&rc32434_wdt_miscdev);
if (ret < 0) {
pr_err("failed to register watchdog device\n");
- goto unmap;
+ return ret;
}
pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n",
timeout);
return 0;
-
-unmap:
- iounmap(wdt_reg);
- return ret;
}
static int rc32434_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&rc32434_wdt_miscdev);
- iounmap(wdt_reg);
return 0;
}
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index 0040451aec1d..3dd8ed28adc8 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -183,7 +183,7 @@ static int riowd_probe(struct platform_device *op)
goto out;
err = -ENOMEM;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
if (!p)
goto out;
@@ -192,7 +192,7 @@ static int riowd_probe(struct platform_device *op)
p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
if (!p->regs) {
pr_err("Cannot map registers\n");
- goto out_free;
+ goto out;
}
/* Make miscdev useable right away */
riowd_device = p;
@@ -206,27 +206,23 @@ static int riowd_probe(struct platform_device *op)
pr_info("Hardware watchdog [%i minutes], regs at %p\n",
riowd_timeout, p->regs);
- dev_set_drvdata(&op->dev, p);
+ platform_set_drvdata(op, p);
return 0;
out_iounmap:
riowd_device = NULL;
of_iounmap(&op->resource[0], p->regs, 2);
-out_free:
- kfree(p);
-
out:
return err;
}
static int riowd_remove(struct platform_device *op)
{
- struct riowd *p = dev_get_drvdata(&op->dev);
+ struct riowd *p = platform_get_drvdata(op);
misc_deregister(&riowd_miscdev);
of_iounmap(&op->resource[0], p->regs, 2);
- kfree(p);
return 0;
}
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 3a9f6961db2d..6a22cf5d35bd 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -358,7 +358,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
ret = s3c2410wdt_cpufreq_register();
if (ret < 0) {
- pr_err("failed to register cpufreq\n");
+ dev_err(dev, "failed to register cpufreq\n");
goto err_clk;
}
@@ -448,12 +448,12 @@ static void s3c2410wdt_shutdown(struct platform_device *dev)
s3c2410wdt_stop(&s3c2410_wdd);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static unsigned long wtcon_save;
static unsigned long wtdat_save;
-static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
+static int s3c2410wdt_suspend(struct device *dev)
{
/* Save watchdog state, and turn it off. */
wtcon_save = readl(wdt_base + S3C2410_WTCON);
@@ -465,7 +465,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
return 0;
}
-static int s3c2410wdt_resume(struct platform_device *dev)
+static int s3c2410wdt_resume(struct device *dev)
{
/* Restore watchdog state. */
@@ -473,16 +473,15 @@ static int s3c2410wdt_resume(struct platform_device *dev)
writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
writel(wtcon_save, wdt_base + S3C2410_WTCON);
- pr_info("watchdog %sabled\n",
+ dev_info(dev, "watchdog %sabled\n",
(wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
return 0;
}
+#endif
-#else
-#define s3c2410wdt_suspend NULL
-#define s3c2410wdt_resume NULL
-#endif /* CONFIG_PM */
+static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
+ s3c2410wdt_resume);
#ifdef CONFIG_OF
static const struct of_device_id s3c2410_wdt_match[] = {
@@ -496,11 +495,10 @@ static struct platform_driver s3c2410wdt_driver = {
.probe = s3c2410wdt_probe,
.remove = s3c2410wdt_remove,
.shutdown = s3c2410wdt_shutdown,
- .suspend = s3c2410wdt_suspend,
- .resume = s3c2410wdt_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",
+ .pm = &s3c2410wdt_pm_ops,
.of_match_table = of_match_ptr(s3c2410_wdt_match),
},
};
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index 25c7a3f9652d..ea5d84a1fdad 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -208,7 +208,7 @@ static long sbwdog_ioctl(struct file *file, unsigned int cmd,
* get the remaining count from the ... count register
* which is 1*8 before the config register
*/
- ret = put_user(__raw_readq(user_dog - 8) / 1000000, p);
+ ret = put_user((u32)__raw_readq(user_dog - 8) / 1000000, p);
break;
}
return ret;
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 6185af2b3310..5bca79457768 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -241,7 +241,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
wdt->dev = &pdev->dev;
- wdt->clk = clk_get(&pdev->dev, NULL);
+ wdt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(wdt->clk)) {
/*
* Clock framework support is optional, continue on
@@ -251,10 +251,8 @@ static int sh_wdt_probe(struct platform_device *pdev)
}
wdt->base = devm_ioremap_resource(wdt->dev, res);
- if (IS_ERR(wdt->base)) {
- rc = PTR_ERR(wdt->base);
- goto err;
- }
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
watchdog_set_nowayout(&sh_wdt_dev, nowayout);
watchdog_set_drvdata(&sh_wdt_dev, wdt);
@@ -277,7 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
rc = watchdog_register_device(&sh_wdt_dev);
if (unlikely(rc)) {
dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
- goto err;
+ return rc;
}
init_timer(&wdt->timer);
@@ -292,23 +290,15 @@ static int sh_wdt_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
-
-err:
- clk_put(wdt->clk);
-
- return rc;
}
static int sh_wdt_remove(struct platform_device *pdev)
{
struct sh_wdt *wdt = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
watchdog_unregister_device(&sh_wdt_dev);
pm_runtime_disable(&pdev->dev);
- clk_put(wdt->clk);
return 0;
}
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index fe83beb8f1b7..b68b1e519d53 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -152,7 +152,6 @@ static struct watchdog_ops softdog_ops = {
.owner = THIS_MODULE,
.start = softdog_ping,
.stop = softdog_stop,
- .ping = softdog_ping,
.set_timeout = softdog_set_timeout,
};
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 8872642505c0..58df98aec122 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -231,7 +231,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
goto err;
}
- wdt->clk = clk_get(&adev->dev, NULL);
+ wdt->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(wdt->clk)) {
dev_warn(&adev->dev, "Clock not found\n");
ret = PTR_ERR(wdt->clk);
@@ -251,15 +251,13 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
if (ret) {
dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
ret);
- goto err_register;
+ goto err;
}
amba_set_drvdata(adev, wdt);
dev_info(&adev->dev, "registration successful\n");
return 0;
-err_register:
- clk_put(wdt->clk);
err:
dev_err(&adev->dev, "Probe Failed!!!\n");
return ret;
@@ -272,7 +270,6 @@ static int sp805_wdt_remove(struct amba_device *adev)
watchdog_unregister_device(&wdt->wdd);
amba_set_drvdata(adev, NULL);
watchdog_set_drvdata(&wdt->wdd, NULL);
- clk_put(wdt->clk);
return 0;
}
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index b8a92459f10f..4da59b4d73f0 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -396,7 +396,7 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
struct resource *r1, *r2;
int error = 0;
- wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL);
+ wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
if (!wdt) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
@@ -405,44 +405,22 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r1) {
dev_err(&pdev->dev, "failed to get memory resource\n");
- error = -ENODEV;
- goto fail;
+ return -ENODEV;
}
- r1 = request_mem_region(r1->start, resource_size(r1), pdev->name);
- if (!r1) {
- dev_err(&pdev->dev, "cannot request memory region\n");
- error = -EBUSY;
- goto fail;
- }
-
- wdt->control_reg = ioremap(r1->start, resource_size(r1));
- if (!wdt->control_reg) {
- dev_err(&pdev->dev, "failed to map memory\n");
- error = -ENODEV;
- goto fail_free_control;
- }
+ wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
+ if (IS_ERR(wdt->control_reg))
+ return PTR_ERR(wdt->control_reg);
r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!r2) {
dev_err(&pdev->dev, "failed to get memory resource\n");
- error = -ENODEV;
- goto fail_unmap_control;
- }
-
- r2 = request_mem_region(r2->start, resource_size(r2), pdev->name);
- if (!r2) {
- dev_err(&pdev->dev, "cannot request memory region\n");
- error = -EBUSY;
- goto fail_unmap_control;
+ return -ENODEV;
}
- wdt->feed_reg = ioremap(r2->start, resource_size(r2));
- if (!wdt->feed_reg) {
- dev_err(&pdev->dev, "failed to map memory\n");
- error = -ENODEV;
- goto fail_free_feed;
- }
+ wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2);
+ if (IS_ERR(wdt->feed_reg))
+ return PTR_ERR(wdt->feed_reg);
platform_set_drvdata(pdev, wdt);
ts72xx_wdt_pdev = pdev;
@@ -455,45 +433,20 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
error = misc_register(&ts72xx_wdt_miscdev);
if (error) {
dev_err(&pdev->dev, "failed to register miscdev\n");
- goto fail_unmap_feed;
+ return error;
}
dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
return 0;
-
-fail_unmap_feed:
- platform_set_drvdata(pdev, NULL);
- iounmap(wdt->feed_reg);
-fail_free_feed:
- release_mem_region(r2->start, resource_size(r2));
-fail_unmap_control:
- iounmap(wdt->control_reg);
-fail_free_control:
- release_mem_region(r1->start, resource_size(r1));
-fail:
- kfree(wdt);
- return error;
}
static int ts72xx_wdt_remove(struct platform_device *pdev)
{
- struct ts72xx_wdt *wdt = platform_get_drvdata(pdev);
- struct resource *res;
int error;
error = misc_deregister(&ts72xx_wdt_miscdev);
- platform_set_drvdata(pdev, NULL);
-
- iounmap(wdt->feed_reg);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- release_mem_region(res->start, resource_size(res));
-
- iounmap(wdt->control_reg);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
- kfree(wdt);
return error;
}
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 0f03106f7516..2d4535dc2676 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -90,10 +90,8 @@ static int twl4030_wdt_probe(struct platform_device *pdev)
twl4030_wdt_stop(wdt);
ret = watchdog_register_device(wdt);
- if (ret) {
- platform_set_drvdata(pdev, NULL);
+ if (ret)
return ret;
- }
return 0;
}
@@ -103,7 +101,6 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
struct watchdog_device *wdt = platform_get_drvdata(pdev);
watchdog_unregister_device(wdt);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index faf4e189fe42..6aaefbad303e 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -469,8 +469,10 @@ static int watchdog_release(struct inode *inode, struct file *file)
* or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
* watchdog_stop will fail.
*/
- if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
- !(wdd->info->options & WDIOF_MAGICCLOSE))
+ if (!test_bit(WDOG_ACTIVE, &wdd->status))
+ err = 0;
+ else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+ !(wdd->info->options & WDIOF_MAGICCLOSE))
err = watchdog_stop(wdd);
/* If the watchdog was not stopped, send a keepalive ping */
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 0a77655cda60..3045debd5411 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -162,31 +162,6 @@ static void wdrtas_timer_stop(void)
}
/**
- * wdrtas_log_scanned_event - logs an event we received during keepalive
- *
- * wdrtas_log_scanned_event prints a message to the log buffer dumping
- * the results of the last event-scan call
- */
-static void wdrtas_log_scanned_event(void)
-{
- int i;
-
- for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
- pr_info("dumping event (line %i/%i), data = "
- "%02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n",
- (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
- wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
- wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
- wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
- wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
- wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
- wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
- wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
- wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
-}
-
-/**
* wdrtas_timer_keepalive - resets watchdog timer to keep system alive
*
* wdrtas_timer_keepalive restarts the watchdog timer by calling the
@@ -205,7 +180,9 @@ static void wdrtas_timer_keepalive(void)
if (result < 0)
pr_err("event-scan failed: %li\n", result);
if (result == 0)
- wdrtas_log_scanned_event();
+ print_hex_dump(KERN_INFO, "dumping event, data: ",
+ DUMP_PREFIX_OFFSET, 16, 1,
+ wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false);
} while (result == 0);
}
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 9dcb6d082277..d4e47eda4182 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -247,9 +247,10 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
if (pdata->update_gpio) {
- ret = gpio_request_one(pdata->update_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW,
- "Watchdog update");
+ ret = devm_gpio_request_one(&pdev->dev,
+ pdata->update_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "Watchdog update");
if (ret < 0) {
dev_err(wm831x->dev,
"Failed to request update GPIO: %d\n",
@@ -270,7 +271,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
} else {
dev_err(wm831x->dev,
"Failed to unlock security key: %d\n", ret);
- goto err_gpio;
+ goto err;
}
}
@@ -278,29 +279,23 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
ret);
- goto err_gpio;
+ goto err;
}
- dev_set_drvdata(&pdev->dev, driver_data);
+ platform_set_drvdata(pdev, driver_data);
return 0;
-err_gpio:
- if (driver_data->update_gpio)
- gpio_free(driver_data->update_gpio);
err:
return ret;
}
static int wm831x_wdt_remove(struct platform_device *pdev)
{
- struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev);
+ struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev);
watchdog_unregister_device(&driver_data->wdt);
- if (driver_data->update_gpio)
- gpio_free(driver_data->update_gpio);
-
return 0;
}